Merge two objects without overriding

I have a defaultObject object:

var default = { abc: "123", def: "456", ghi: { jkl: "789", mno: "012" } }; 

And I have something else:

 var values = { abc: "zzz", ghi: { jkl: "yyy", } }; 

How can I combine these 2 objects with the following result (without overriding)?

 var values = { abc: "zzz", def: "456", ghi: { jkl: "yyy", mno: "012" } }; 

(I do not want to change the default object!)

+8
source share
5 answers

Since ES2015 is now supported in all modern browsers, the native Object.assign can be used to extend objects

 Object.assign({}, _default, values) 

Object.assign

Note that default is a reserved keyword and cannot be used as a variable name.


Original answer written in 2013:

Since this is tagged with jQuery, you can use $ .extend for a simple cross-browser solution.

 var temp = {}; $.extend(true, temp, _default, values); values = temp; 

+4
source

Also, if you are satisfied with ES6:

 Object.assign({}, default, values) 
+10
source

For those not using jQuery, here comes the vanilla-js solution.

Decision

 function extend (target) { for(var i=1; i<arguments.length; ++i) { var from = arguments[i]; if(typeof from !== 'object') continue; for(var j in from) { if(from.hasOwnProperty(j)) { target[j] = typeof from[j]==='object' ? extend({}, target[j], from[j]) : from[j]; } } } return target; } 

Compressed (with Closure Compiler ):

Only 199 characters!

 var extend=function e(c){for(var d=1;d<arguments.length;++d){var a=arguments[d];if("object"===typeof a)for(var b in a)a.hasOwnProperty(b)&&(c[b]="object"===typeof a[b]?e({},c[b],a[b]):a[b])}return c} 

How to use :

 extend(target, obj1, obj2); // returns target 

If you want to combine, use

 var merged = extend({}, obj1, obj2); 

Functions

  • He does not look at prototype objects.
  • Ignores no objects.
  • It is recursive to combine properties that are objects.
  • Objects referenced by the target properties, if extended, are replaced with new ones, but the original ones are not changed.
  • In the case of identical property names, the combined value will be the union of the objects after the last (in the order of arguments) value other than the object. Or, if the latter is not an object, itself.

<strong> Examples:

 extend({}, {a:1}, {a:2}); // {a:2} extend({}, {a:1}, {b:2}); // {a:1, b:2} extend({}, {a: {b:1}}, {a: {b:2}}); // {a: {b:2}} extend({}, {a: {b:1}}, {a: {c:2}}); // {a: {b:2, c:2}} extend({}, {a: {a:1}}, {a: {b:2}}, {a: 'whatever non object'}); // {a: "whatever non object"} extend({}, {a: {a:1}}, {a: {b:2}}, {a: 'whatever non object'}, {a: {c:3}},{a: {d:4}}); // {a: {c:3, d:4}} 

Attention

Remember that if the browser is not smart enough, it can be captured in an endless loop:

 var obj1={}, obj2={}; obj1.me=obj1; obj2.me=obj2; extend({},obj1,obj2); 

If the browser is smart enough, it may throw an error or return {me: undefined} or something else.

Note that this warning also applies if you are using jQuery $.extend .

+7
source

Another way would be to simply increase the default value (instead of overriding the default value on the contrary)

 Object.assign(value, default) // values of default overrides value default = value // reset default to value 

The caveat here is that the contents of the value also change. The surface - the library is neither needed nor simpler than the usual vanilla solution above.

+2
source

My version, based on Oriol's answer, adds a check for arrays to prevent arrays from turning into fun {'0': ..., '1': ...} thingys

 function extend (target) { for(var i=1; i<arguments.length; ++i) { var from = arguments[i]; if(typeof from !== 'object') continue; for(var j in from) { if(from.hasOwnProperty(j)) { target[j] = typeof from[j]==='object' && !Array.isArray(from[j]) ? extend({}, target[j], from[j]) : from[j]; } } } return target; } 
+1
source

All Articles