Inverse of jQuery.extend(true, …)
I'm looking to reduce storage requirements for JSON data by deltifying it against a known set of defaults. Basically, what I want is an inverse for jQuery's .extend()
function, such that the following test passes for arbitrary JSON-compatible objects:
function test_delta(defaults, delta) {
var current = $.extend(true, {}, defaults, delta);
QUnit.same(get_delta(current, def开发者_如何学Pythonaults), delta);
}
Before I start writing my own get_delta()
, is anyone aware of an existing implementation?
What you're really looking for is an object diff(erential) algorithm.
Not too difficult to write -
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' }
As you can see this is a very basic implementation - you could extend this to provide a complete differential by returning additions to obj2 in a separate object.
This code isn't bug free, object protoypes and functions will be handled differently in different browsers, but it should suffice as a demonstration for data structures.
Try something like that:
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;
}
});
usage:
var result = $.deltaExtend(true, {}, defaults, delta);
$(result).data('delta') //returns delta object
$(result).data('defaults') //returns default object
It also can be tweaked to get it working for N objects, just requires a little more thinking.
I know this is a little late to be relevant to the topic starter, but you might want to have a look at the _.omit(object, *keys)
function from Underscore.js. It does just that.
精彩评论