Reputation: 8711
I have two javascript objects:
var a = {
x: 1,
y: {
faz: 'hello',
baz: ''
},
z: [1, 2]
};
var defaults = {
x: 2,
y: {
faz: '',
baz: ''
},
z: [1, 2]
};
I want to only keep the fields of a
that are different from the default:
a = remove_defaults(a, defaults); // <---- i need this fnc
{
x: 1,
y: {
faz: 'hello'
}
}
The goal is to remove default values from an object that serves as a state (via URL). The state can have nested fields, so a shallow compare is not enough. The leaf values are all primitive (number, string, bool).
(this is a bit like the opposite of underscore.js
's _.defaults()
method)
What is the best way to achieve this?
The solution can use underscore.js
if that helps, but no jquery
.
Upvotes: 6
Views: 1227
Reputation: 16949
Try this:
function removeDuplicates(a, defaults, result) {
for (var i in a) {
if (i in defaults) {
if (typeof a[i] == "object"
&& typeof defaults[i] == "object"
&& Object.prototype.toString.call(defaults[i]) !== '[object Array]') {
result[i] = removeDuplicates(a[i], defaults[i], {});
} else if (a[i] !== defaults[i]) {
result[i] = a[i];
}
} else {
result[i] = a[i];
}
}
return result;
}
var result = removeDuplicates(a, defaults, {});
Upvotes: 3
Reputation: 8711
My own take:
function no_defaults(obj, defaults) {
if ((obj instanceof Array) && (defaults instanceof Array)) {
var result = _.difference(obj, defaults);
return _.isEmpty(result) ? undefined : result;
}
if ((obj instanceof Array) || (defaults instanceof Array))
return _.clone(obj);
if (typeof obj == "object" && typeof defaults == "object") {
var result = {};
for (var prop in obj) {
var res = prop in defaults ? no_defaults(obj[prop], defaults[prop]) : _.clone(obj[prop]);
if (res !== undefined)
result[prop] = res;
}
return _.isEmpty(result) ? undefined : result;
}
return _.isEqual(obj, defaults) ? undefined : _.clone(obj);
}
Note this deep-processes objects, but not arrays. Arrays are only processed for shallow difference of their direct elements -- if the elements themselves need no_default
ing, this function won't do. But this is fine for my intended use case.
Upvotes: 0
Reputation: 7882
function remove_defaults(obj, defaults) {
for (var i in obj) {
if (typeof obj[i] == 'object') {
obj[i] = remove_defaults(obj[i], defaults[i]);
continue;
}
if (defaults[i] !== undefined && obj[i] == defaults[i]) {
delete obj[i];
}
}
return obj;
}
Fiddle: http://jsfiddle.net/ybVGq/
Upvotes: 1