2010-08-04 3 views
7

Я ищу, чтобы уменьшить требования к хранилищу данных JSON, делит его на известный набор значений по умолчанию. В общем, что я хочу, является обратным для .extend() функции JQuery, таким, что следующий тест проходит для произвольных JSON-совместимых объектов:Обратный jQuery.extend (true, ...)

function test_delta(defaults, delta) { 
    var current = $.extend(true, {}, defaults, delta); 

    QUnit.same(get_delta(current, defaults), delta); 
} 

Перед тем, как начать писать свой собственный get_delta(), кто-нибудь в курсе существующей реализации?

+0

Вам нужно будет справиться с этим самим, жестким (вложенным циклом) способом. Как вы, наверное, знаете. Еще веселее, если ваши данные JSON имеют произвольную глубину. –

+0

Да, я уже придумал некоторые интересные случаи; поэтому я подумал, что я попрошу «SO оракул», прежде чем копаться в нем сам. Ах хорошо. :-) –

+0

Хорошим местом для начала будет просмотр функции jQuery.fn.extend в источнике [jQuery] (http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js). – calvinf

ответ

1

То, что вы действительно ищете, является алгоритмом сравнения объектов (erential).

Не слишком трудно писать -



function diff (obj1, obj2) { 
    var delta = {}; 

    for (var x in obj1) { 
     if (obj2.hasOwnProperty(x)) { 
      if (typeof obj2[x] == "object") { 
       //recurse nested objects/arrays 
       delta[x] = diff(obj1[x], obj2[x]); 
      } 
      else { 
       //if obj2 doesn't match then - modified attribute 
       if (obj2[x] != obj1[x]) { 
        delta[x] = obj1[x]; 
       } 
      }   
     } 
     else { 
      //obj2 doesn't have this - new attribute 
      delta[x] = obj1[x]; 
     } 
    } 

    return delta; 
} 

alert( 
    JSON.stringify(
    diff({ hello : 'world', gone : 'fishing' }, 
      { hello : 'world' }) 
) 
); 

//outputs: 
{ gone : 'fishing' } 

Как вы можете видеть, что это очень простая реализация - вы можете расширить это, чтобы обеспечить полный дифференциал, возвращая дополнения к obj2 в отдельном объекте.

Этот код не является ошибкой, объекты protoypes и функции будут обрабатываться по-разному в разных браузерах, но это должно быть достаточным в качестве демонстрации для структур данных.

+0

Я сделал удар по реализации моего собственного, но было достаточно неясных случаев края (особенно с массивами и удаленными свойствами), которые мы решили просто увеличить колонку базы данных вместо этого. –

1

попробовать что-то вроде этого:

jQuery.extend({ 
    deltaExtend: function(deep, target, defaults, delta){ 
     var result = jQuery.extend.apply(jQuery, arguments); 
     jQuery(result).data('delta', delta); 
     jQuery(result).data('defaults', defaults); 
     return result; 
    } 
}); 

использование:

var result = $.deltaExtend(true, {}, defaults, delta); 
$(result).data('delta') //returns delta object 
$(result).data('defaults') //returns default object 

Он также может быть изменен, чтобы получить его работу для N объектов, просто требует немного больше думать.

+0

Это очень интересная идея! К сожалению, '$ .extend' не используется при создании объекта результата в моем случае. Это было для системы портала, где каждый портлет мог определять свои собственные настройки по умолчанию. «Текущие» настройки затем будут свободно изменяться в течение всего срока службы страницы, и когда пришло время сохранить состояние портлета на сервере, я надеялся выполнить «слепую» дельта, чтобы уменьшить требования к хранилищу. –

+0

У меня есть другое решение, какие браузеры вы поддерживаете, и какие версии, в частности, поддерживают IE

1

Я знаю, что это немного поздно, чтобы иметь отношение к теме стартер, но вы можете захотеть взглянуть на функцию _.omit(object, *keys) от Underscore.js. Он делает именно это.

+0

Но откуда вы знаете «ключи»? – Bergi

+0

Ключи поступают из объекта, в котором хранятся значения по умолчанию. '_.keys (defaultObject)' дает вам массив своих ключей. – oley

+0

Возможно, вы должны были упомянуть об этом в своем ответе ... И обратите внимание, что этот метод работает только для * добавленных * свойств, а не для всех * измененных *. – Bergi

Смежные вопросы