Related
I need to be able to merge two (very simple) JavaScript objects at runtime. For example I'd like to:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
obj1.merge(obj2);
//obj1 now has three properties: food, car, and animal
Is there a built in way to do this? I do not need recursion, and I do not need to merge functions, just methods on flat objects.
ECMAScript 2018 Standard Method
You would use object spread:
let merged = {...obj1, ...obj2};
merged is now the union of obj1 and obj2. Properties in obj2 will overwrite those in obj1.
/** There's no limit to the number of objects you can merge.
* Later properties overwrite earlier properties with the same name. */
const allRules = {...obj1, ...obj2, ...obj3};
Here is also the MDN documentation for this syntax. If you're using babel you'll need the #babel/plugin-proposal-object-rest-spread plugin for it to work (This plugin is included in #babel/preset-env, in ES2018).
ECMAScript 2015 (ES6) Standard Method
/* For the case in question, you would do: */
Object.assign(obj1, obj2);
/** There's no limit to the number of objects you can merge.
* All objects get merged into the first object.
* Only the object in the first argument is mutated and returned.
* Later properties overwrite earlier properties with the same name. */
const allRules = Object.assign({}, obj1, obj2, obj3, etc);
(see MDN JavaScript Reference)
Method for ES5 and Earlier
for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
Note that this will simply add all attributes of obj2 to obj1 which might not be what you want if you still want to use the unmodified obj1.
If you're using a framework that craps all over your prototypes then you have to get fancier with checks like hasOwnProperty, but that code will work for 99% of cases.
Example function:
/**
* Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
* #param obj1
* #param obj2
* #returns obj3 a new object based on obj1 and obj2
*/
function merge_options(obj1,obj2){
var obj3 = {};
for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
return obj3;
}
jQuery also has a utility for this: http://api.jquery.com/jQuery.extend/.
Taken from the jQuery documentation:
// Merge options object into settings object
var settings = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
jQuery.extend(settings, options);
// Now the content of settings object is the following:
// { validate: true, limit: 5, name: "bar" }
The above code will mutate the existing object named settings.
If you want to create a new object without modifying either argument, use this:
var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
/* Merge defaults and options, without modifying defaults */
var settings = $.extend({}, defaults, options);
// The content of settings variable is now the following:
// {validate: true, limit: 5, name: "bar"}
// The 'defaults' and 'options' variables remained the same.
The Harmony ECMAScript 2015 (ES6) specifies Object.assign which will do this.
Object.assign(obj1, obj2);
Current browser support is getting better, but if you're developing for browsers that don't have support, you can use a polyfill.
I googled for code to merge object properties and ended up here. However since there wasn't any code for recursive merge I wrote it myself. (Maybe jQuery extend is recursive BTW?) Anyhow, hopefully someone else will find it useful as well.
(Now the code does not use Object.prototype :)
Code
/*
* Recursively merge properties of two objects
*/
function MergeRecursive(obj1, obj2) {
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if ( obj2[p].constructor==Object ) {
obj1[p] = MergeRecursive(obj1[p], obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch(e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
An example
o1 = { a : 1,
b : 2,
c : {
ca : 1,
cb : 2,
cc : {
cca : 100,
ccb : 200 } } };
o2 = { a : 10,
c : {
ca : 10,
cb : 20,
cc : {
cca : 101,
ccb : 202 } } };
o3 = MergeRecursive(o1, o2);
Produces object o3 like
o3 = { a : 10,
b : 2,
c : {
ca : 10,
cb : 20,
cc : {
cca : 101,
ccb : 202 } } };
Note that underscore.js's extend-method does this in a one-liner:
_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
Similar to jQuery extend(), you have the same function in AngularJS:
// Merge the 'options' object into the 'settings' object
var settings = {validate: false, limit: 5, name: "foo"};
var options = {validate: true, name: "bar"};
angular.extend(settings, options);
I need to merge objects today, and this question (and answers) helped me a lot. I tried some of the answers, but none of them fit my needs, so I combined some of the answers, added something myself and came up with a new merge function. Here it is:
var merge = function() {
var obj = {},
i = 0,
il = arguments.length,
key;
for (; i < il; i++) {
for (key in arguments[i]) {
if (arguments[i].hasOwnProperty(key)) {
obj[key] = arguments[i][key];
}
}
}
return obj;
};
Some example usages:
var t1 = {
key1: 1,
key2: "test",
key3: [5, 2, 76, 21]
};
var t2 = {
key1: {
ik1: "hello",
ik2: "world",
ik3: 3
}
};
var t3 = {
key2: 3,
key3: {
t1: 1,
t2: 2,
t3: {
a1: 1,
a2: 3,
a4: [21, 3, 42, "asd"]
}
}
};
console.log(merge(t1, t2));
console.log(merge(t1, t3));
console.log(merge(t2, t3));
console.log(merge(t1, t2, t3));
console.log(merge({}, t1, { key1: 1 }));
You can use the object spread syntax to achieve this. It's a part of ES2018 and beyond.
const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { animal: 'dog' };
const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
The given solutions should be modified to check source.hasOwnProperty(property) in the for..in loops before assigning - otherwise, you end up copying the properties of the whole prototype chain, which is rarely desired...
Merge properties of N objects in one line of code
An Object.assign method is part of the ECMAScript 2015 (ES6) standard and does exactly what you need. (IE not supported)
var clone = Object.assign({}, obj);
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object.
Read more...
The polyfill to support older browsers:
if (!Object.assign) {
Object.defineProperty(Object, 'assign', {
enumerable: false,
configurable: true,
writable: true,
value: function(target) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert first argument to object');
}
var to = Object(target);
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
if (nextSource === undefined || nextSource === null) {
continue;
}
nextSource = Object(nextSource);
var keysArray = Object.keys(nextSource);
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
var nextKey = keysArray[nextIndex];
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
if (desc !== undefined && desc.enumerable) {
to[nextKey] = nextSource[nextKey];
}
}
}
return to;
}
});
}
The following two are probably a good starting point. lodash also has a customizer function for those special needs!
_.extend (http://underscorejs.org/#extend)
_.merge (https://lodash.com/docs#merge)
Here's my stab which
Supports deep merge
Does not mutate arguments
Takes any number of arguments
Does not extend the object prototype
Does not depend on another library (jQuery, MooTools, Underscore.js, etc.)
Includes check for hasOwnProperty
Is short :)
/*
Recursively merge properties and return new object
obj1 <- obj2 [ <- ... ]
*/
function merge () {
var dst = {}
,src
,p
,args = [].splice.call(arguments, 0)
;
while (args.length > 0) {
src = args.splice(0, 1)[0];
if (toString.call(src) == '[object Object]') {
for (p in src) {
if (src.hasOwnProperty(p)) {
if (toString.call(src[p]) == '[object Object]') {
dst[p] = merge(dst[p] || {}, src[p]);
} else {
dst[p] = src[p];
}
}
}
}
}
return dst;
}
Example:
a = {
"p1": "p1a",
"p2": [
"a",
"b",
"c"
],
"p3": true,
"p5": null,
"p6": {
"p61": "p61a",
"p62": "p62a",
"p63": [
"aa",
"bb",
"cc"
],
"p64": {
"p641": "p641a"
}
}
};
b = {
"p1": "p1b",
"p2": [
"d",
"e",
"f"
],
"p3": false,
"p4": true,
"p6": {
"p61": "p61b",
"p64": {
"p642": "p642b"
}
}
};
c = {
"p1": "p1c",
"p3": null,
"p6": {
"p62": "p62c",
"p64": {
"p643": "p641c"
}
}
};
d = merge(a, b, c);
/*
d = {
"p1": "p1c",
"p2": [
"d",
"e",
"f"
],
"p3": null,
"p5": null,
"p6": {
"p61": "p61b",
"p62": "p62c",
"p63": [
"aa",
"bb",
"cc"
],
"p64": {
"p641": "p641a",
"p642": "p642b",
"p643": "p641c"
}
},
"p4": true
};
*/
Just by the way, what you're all doing is overwriting properties, not merging...
This is how JavaScript objects area really merged: Only keys in the to object which are not objects themselves will be overwritten by from. Everything else will be really merged. Of course you can change this behaviour to not overwrite anything which exists like only if to[n] is undefined, etc...:
var realMerge = function (to, from) {
for (n in from) {
if (typeof to[n] != 'object') {
to[n] = from[n];
} else if (typeof from[n] == 'object') {
to[n] = realMerge(to[n], from[n]);
}
}
return to;
};
Usage:
var merged = realMerge(obj1, obj2);
Object.assign()
ECMAScript 2015 (ES6)
This is a new technology, part of the ECMAScript 2015 (ES6) standard.
This technology's specification has been finalized, but check the compatibility table for usage and implementation status in various browsers.
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed.
For not-too-complicated objects you could use JSON:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'chevy'}
var objMerge;
objMerge = JSON.stringify(obj1) + JSON.stringify(obj2);
// {"food": "pizza","car":"ford"}{"animal":"dog","car":"chevy"}
objMerge = objMerge.replace(/\}\{/, ","); // \_ replace with comma for valid JSON
objMerge = JSON.parse(objMerge); // { food: 'pizza', animal: 'dog', car: 'chevy'}
// Of same keys in both objects, the last object's value is retained_/
Mind you that in this example "}{" must not occur within a string!
There's a library called deepmerge on GitHub: That seems to be getting some traction. It's a standalone, available through both the npm and bower package managers.
I would be inclined to use or improve on this instead of copy-pasting code from answers.
The best way for you to do this is to add a proper property that is non-enumerable using Object.defineProperty.
This way you will still be able to iterate over your objects properties without having the newly created "extend" that you would get if you were to create the property with Object.prototype.extend.
Hopefully this helps:
Object.defineProperty(Object.prototype, "extend", {
enumerable: false,
value: function(from) {
var props = Object.getOwnPropertyNames(from);
var dest = this;
props.forEach(function(name) {
if (name in dest) {
var destination = Object.getOwnPropertyDescriptor(from, name);
Object.defineProperty(dest, name, destination);
}
});
return this;
}
});
Once you have that working, you can do:
var obj = {
name: 'stack',
finish: 'overflow'
}
var replacement = {
name: 'stock'
};
obj.extend(replacement);
I just wrote a blog post about it here: http://onemoredigit.com/post/1527191998/extending-objects-in-node-js
You can simply use jQuery extend
var obj1 = { val1: false, limit: 5, name: "foo" };
var obj2 = { val2: true, name: "bar" };
jQuery.extend(obj1, obj2);
Now obj1 contains all the values of obj1 and obj2
Prototype has this:
Object.extend = function(destination,source) {
for (var property in source)
destination[property] = source[property];
return destination;
}
obj1.extend(obj2) will do what you want.
Wow.. this is the first StackOverflow post I've seen with multiple pages. Apologies for adding another "answer"
ES5 & Earlier
This method is for ES5 & Earlier - there are plenty of other answers addressing ES6.
I did not see any "deep" object merging utilizing the arguments property. Here is my answer - compact & recursive, allowing unlimited object arguments to be passed:
function extend() {
for (var o = {}, i = 0; i < arguments.length; i++) {
// Uncomment to skip arguments that are not objects (to prevent errors)
// if (arguments[i].constructor !== Object) continue;
for (var k in arguments[i]) {
if (arguments[i].hasOwnProperty(k)) {
o[k] = arguments[i][k].constructor === Object
? extend(o[k] || {}, arguments[i][k])
: arguments[i][k];
}
}
}
return o;
}
Example
/**
* Extend objects
*/
function extend() {
for (var o = {}, i = 0; i < arguments.length; i++) {
for (var k in arguments[i]) {
if (arguments[i].hasOwnProperty(k)) {
o[k] = arguments[i][k].constructor === Object
? extend(o[k] || {}, arguments[i][k])
: arguments[i][k];
}
}
}
return o;
}
/**
* Example
*/
document.write(JSON.stringify(extend({
api: 1,
params: {
query: 'hello'
}
}, {
params: {
query: 'there'
}
})));
// outputs {"api": 1, "params": {"query": "there"}}
This answer is now but a drop in the ocean ...
Just if anyone is using Google Closure Library:
goog.require('goog.object');
var a = {'a': 1, 'b': 2};
var b = {'b': 3, 'c': 4};
goog.object.extend(a, b);
// Now object a == {'a': 1, 'b': 3, 'c': 4};
Similar helper function exists for array:
var a = [1, 2];
var b = [3, 4];
goog.array.extend(a, b); // Extends array 'a'
goog.array.concat(a, b); // Returns concatenation of array 'a' and 'b'
**Merging objects is simple using Object.assign or the spread ... operator **
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'BMW' }
var obj3 = {a: "A"}
var mergedObj = Object.assign(obj1,obj2,obj3)
// or using the Spread operator (...)
var mergedObj = {...obj1,...obj2,...obj3}
console.log(mergedObj);
The objects are merged from right to left, this means that objects which have identical properties as the objects to their right will be overriden.
In this example obj2.car overrides obj1.car
I extended David Coallier's method:
Added the possibility to merge multiple objects
Supports deep objects
override parameter (that's detected if the last parameter is a boolean)
If override is false, no property gets overridden but new properties will be added.
Usage:
obj.merge(merges... [, override]);
Here is my code:
Object.defineProperty(Object.prototype, "merge", {
enumerable: false,
value: function () {
var override = true,
dest = this,
len = arguments.length,
props, merge, i, from;
if (typeof(arguments[arguments.length - 1]) === "boolean") {
override = arguments[arguments.length - 1];
len = arguments.length - 1;
}
for (i = 0; i < len; i++) {
from = arguments[i];
if (from != null) {
Object.getOwnPropertyNames(from).forEach(function (name) {
var descriptor;
// nesting
if ((typeof(dest[name]) === "object" || typeof(dest[name]) === "undefined")
&& typeof(from[name]) === "object") {
// ensure proper types (Array rsp Object)
if (typeof(dest[name]) === "undefined") {
dest[name] = Array.isArray(from[name]) ? [] : {};
}
if (override) {
if (!Array.isArray(dest[name]) && Array.isArray(from[name])) {
dest[name] = [];
}
else if (Array.isArray(dest[name]) && !Array.isArray(from[name])) {
dest[name] = {};
}
}
dest[name].merge(from[name], override);
}
// flat properties
else if ((name in dest && override) || !(name in dest)) {
descriptor = Object.getOwnPropertyDescriptor(from, name);
if (descriptor.configurable) {
Object.defineProperty(dest, name, descriptor);
}
}
});
}
}
return this;
}
});
Examples and TestCases:
function clone (obj) {
return JSON.parse(JSON.stringify(obj));
}
var obj = {
name : "trick",
value : "value"
};
var mergeObj = {
name : "truck",
value2 : "value2"
};
var mergeObj2 = {
name : "track",
value : "mergeObj2",
value2 : "value2-mergeObj2",
value3 : "value3"
};
assertTrue("Standard", clone(obj).merge(mergeObj).equals({
name : "truck",
value : "value",
value2 : "value2"
}));
assertTrue("Standard no Override", clone(obj).merge(mergeObj, false).equals({
name : "trick",
value : "value",
value2 : "value2"
}));
assertTrue("Multiple", clone(obj).merge(mergeObj, mergeObj2).equals({
name : "track",
value : "mergeObj2",
value2 : "value2-mergeObj2",
value3 : "value3"
}));
assertTrue("Multiple no Override", clone(obj).merge(mergeObj, mergeObj2, false).equals({
name : "trick",
value : "value",
value2 : "value2",
value3 : "value3"
}));
var deep = {
first : {
name : "trick",
val : "value"
},
second : {
foo : "bar"
}
};
var deepMerge = {
first : {
name : "track",
anotherVal : "wohoo"
},
second : {
foo : "baz",
bar : "bam"
},
v : "on first layer"
};
assertTrue("Deep merges", clone(deep).merge(deepMerge).equals({
first : {
name : "track",
val : "value",
anotherVal : "wohoo"
},
second : {
foo : "baz",
bar : "bam"
},
v : "on first layer"
}));
assertTrue("Deep merges no override", clone(deep).merge(deepMerge, false).equals({
first : {
name : "trick",
val : "value",
anotherVal : "wohoo"
},
second : {
foo : "bar",
bar : "bam"
},
v : "on first layer"
}));
var obj1 = {a: 1, b: "hello"};
obj1.merge({c: 3});
assertTrue(obj1.equals({a: 1, b: "hello", c: 3}));
obj1.merge({a: 2, b: "mom", d: "new property"}, false);
assertTrue(obj1.equals({a: 1, b: "hello", c: 3, d: "new property"}));
var obj2 = {};
obj2.merge({a: 1}, {b: 2}, {a: 3});
assertTrue(obj2.equals({a: 3, b: 2}));
var a = [];
var b = [1, [2, 3], 4];
a.merge(b);
assertEquals(1, a[0]);
assertEquals([2, 3], a[1]);
assertEquals(4, a[2]);
var o1 = {};
var o2 = {a: 1, b: {c: 2}};
var o3 = {d: 3};
o1.merge(o2, o3);
assertTrue(o1.equals({a: 1, b: {c: 2}, d: 3}));
o1.b.c = 99;
assertTrue(o2.equals({a: 1, b: {c: 2}}));
// checking types with arrays and objects
var bo;
a = [];
bo = [1, {0:2, 1:3}, 4];
b = [1, [2, 3], 4];
a.merge(b);
assertTrue("Array stays Array?", Array.isArray(a[1]));
a = [];
a.merge(bo);
assertTrue("Object stays Object?", !Array.isArray(a[1]));
a = [];
a.merge(b);
a.merge(bo);
assertTrue("Object overrides Array", !Array.isArray(a[1]));
a = [];
a.merge(b);
a.merge(bo, false);
assertTrue("Object does not override Array", Array.isArray(a[1]));
a = [];
a.merge(bo);
a.merge(b);
assertTrue("Array overrides Object", Array.isArray(a[1]));
a = [];
a.merge(bo);
a.merge(b, false);
assertTrue("Array does not override Object", !Array.isArray(a[1]));
My equals method can be found here: Object comparison in JavaScript
In MooTools, there's Object.merge():
Object.merge(obj1, obj2);
var firstObject = {
key1 : 'value1',
key2 : 'value2'
};
var secondObject={
...firstObject,
key3 : 'value3',
key4 : 'value4',
key5 : 'value5'
}
console.log(firstObject);
console.log(secondObject);
In Ext JS 4 it can be done as follows:
var mergedObject = Ext.Object.merge(object1, object2)
// Or shorter:
var mergedObject2 = Ext.merge(object1, object2)
See merge( object ) : Object.
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
// result
result: {food: "pizza", car: "ford", animal: "dog"}
Using jQuery.extend() - Link
// Merge obj1 & obj2 to result
var result1 = $.extend( {}, obj1, obj2 );
Using _.merge() - Link
// Merge obj1 & obj2 to result
var result2 = _.merge( {}, obj1, obj2 );
Using _.extend() - Link
// Merge obj1 & obj2 to result
var result3 = _.extend( {}, obj1, obj2 );
Using Object.assign() ECMAScript 2015 (ES6) - Link
// Merge obj1 & obj2 to result
var result4 = Object.assign( {}, obj1, obj2 );
Output of all
obj1: { animal: 'dog' }
obj2: { food: 'pizza', car: 'ford' }
result1: {food: "pizza", car: "ford", animal: "dog"}
result2: {food: "pizza", car: "ford", animal: "dog"}
result3: {food: "pizza", car: "ford", animal: "dog"}
result4: {food: "pizza", car: "ford", animal: "dog"}
Based on Markus' and vsync' answer, this is an expanded version. The function takes any number of arguments. It can be used to set properties on DOM nodes and makes deep copies of values. However, the first argument is given by reference.
To detect a DOM node, the isDOMNode() function is used (see Stack Overflow question JavaScript isDOM — How do you check if a JavaScript Object is a DOM Object?)
It was tested in Opera 11, Firefox 6, Internet Explorer 8 and Google Chrome 16.
Code
function mergeRecursive() {
// _mergeRecursive does the actual job with two arguments.
var _mergeRecursive = function (dst, src) {
if (isDOMNode(src) || typeof src !== 'object' || src === null) {
return dst;
}
for (var p in src) {
if (!src.hasOwnProperty(p))
continue;
if (src[p] === undefined)
continue;
if ( typeof src[p] !== 'object' || src[p] === null) {
dst[p] = src[p];
} else if (typeof dst[p]!=='object' || dst[p] === null) {
dst[p] = _mergeRecursive(src[p].constructor===Array ? [] : {}, src[p]);
} else {
_mergeRecursive(dst[p], src[p]);
}
}
return dst;
}
// Loop through arguments and merge them into the first argument.
var out = arguments[0];
if (typeof out !== 'object' || out === null)
return out;
for (var i = 1, il = arguments.length; i < il; i++) {
_mergeRecursive(out, arguments[i]);
}
return out;
}
Some examples
Set innerHTML and style of a HTML Element
mergeRecursive(
document.getElementById('mydiv'),
{style: {border: '5px solid green', color: 'red'}},
{innerHTML: 'Hello world!'});
Merge arrays and objects. Note that undefined can be used to preserv values in the lefthand array/object.
o = mergeRecursive({a:'a'}, [1,2,3], [undefined, null, [30,31]], {a:undefined, b:'b'});
// o = {0:1, 1:null, 2:[30,31], a:'a', b:'b'}
Any argument not beeing a JavaScript object (including null) will be ignored. Except for the first argument, also DOM nodes are discarded. Beware that i.e. strings, created like new String() are in fact objects.
o = mergeRecursive({a:'a'}, 1, true, null, undefined, [1,2,3], 'bc', new String('de'));
// o = {0:'d', 1:'e', 2:3, a:'a'}
If you want to merge two objects into a new (without affecting any of the two) supply {} as first argument
var a={}, b={b:'abc'}, c={c:'cde'}, o;
o = mergeRecursive(a, b, c);
// o===a is true, o===b is false, o===c is false
Edit (by ReaperSoon):
To also merge arrays
function mergeRecursive(obj1, obj2) {
if (Array.isArray(obj2)) { return obj1.concat(obj2); }
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if ( obj2[p].constructor==Object ) {
obj1[p] = mergeRecursive(obj1[p], obj2[p]);
} else if (Array.isArray(obj2[p])) {
obj1[p] = obj1[p].concat(obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch(e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
It seems like this should be all you need:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
var obj3 = { ...obj1, ...obj2 }
After that obj3 should now have the following value:
{food: "pizza", car: "ford", animal: "dog"}
Try it out here:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
var obj3 = { ...obj1, ...obj2 }
console.log(obj3);
You should use lodash's defaultsDeep
_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }
I need to be able to merge two (very simple) JavaScript objects at runtime. For example I'd like to:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
obj1.merge(obj2);
//obj1 now has three properties: food, car, and animal
Is there a built in way to do this? I do not need recursion, and I do not need to merge functions, just methods on flat objects.
ECMAScript 2018 Standard Method
You would use object spread:
let merged = {...obj1, ...obj2};
merged is now the union of obj1 and obj2. Properties in obj2 will overwrite those in obj1.
/** There's no limit to the number of objects you can merge.
* Later properties overwrite earlier properties with the same name. */
const allRules = {...obj1, ...obj2, ...obj3};
Here is also the MDN documentation for this syntax. If you're using babel you'll need the #babel/plugin-proposal-object-rest-spread plugin for it to work (This plugin is included in #babel/preset-env, in ES2018).
ECMAScript 2015 (ES6) Standard Method
/* For the case in question, you would do: */
Object.assign(obj1, obj2);
/** There's no limit to the number of objects you can merge.
* All objects get merged into the first object.
* Only the object in the first argument is mutated and returned.
* Later properties overwrite earlier properties with the same name. */
const allRules = Object.assign({}, obj1, obj2, obj3, etc);
(see MDN JavaScript Reference)
Method for ES5 and Earlier
for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
Note that this will simply add all attributes of obj2 to obj1 which might not be what you want if you still want to use the unmodified obj1.
If you're using a framework that craps all over your prototypes then you have to get fancier with checks like hasOwnProperty, but that code will work for 99% of cases.
Example function:
/**
* Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
* #param obj1
* #param obj2
* #returns obj3 a new object based on obj1 and obj2
*/
function merge_options(obj1,obj2){
var obj3 = {};
for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
return obj3;
}
jQuery also has a utility for this: http://api.jquery.com/jQuery.extend/.
Taken from the jQuery documentation:
// Merge options object into settings object
var settings = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
jQuery.extend(settings, options);
// Now the content of settings object is the following:
// { validate: true, limit: 5, name: "bar" }
The above code will mutate the existing object named settings.
If you want to create a new object without modifying either argument, use this:
var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
/* Merge defaults and options, without modifying defaults */
var settings = $.extend({}, defaults, options);
// The content of settings variable is now the following:
// {validate: true, limit: 5, name: "bar"}
// The 'defaults' and 'options' variables remained the same.
The Harmony ECMAScript 2015 (ES6) specifies Object.assign which will do this.
Object.assign(obj1, obj2);
Current browser support is getting better, but if you're developing for browsers that don't have support, you can use a polyfill.
I googled for code to merge object properties and ended up here. However since there wasn't any code for recursive merge I wrote it myself. (Maybe jQuery extend is recursive BTW?) Anyhow, hopefully someone else will find it useful as well.
(Now the code does not use Object.prototype :)
Code
/*
* Recursively merge properties of two objects
*/
function MergeRecursive(obj1, obj2) {
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if ( obj2[p].constructor==Object ) {
obj1[p] = MergeRecursive(obj1[p], obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch(e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
An example
o1 = { a : 1,
b : 2,
c : {
ca : 1,
cb : 2,
cc : {
cca : 100,
ccb : 200 } } };
o2 = { a : 10,
c : {
ca : 10,
cb : 20,
cc : {
cca : 101,
ccb : 202 } } };
o3 = MergeRecursive(o1, o2);
Produces object o3 like
o3 = { a : 10,
b : 2,
c : {
ca : 10,
cb : 20,
cc : {
cca : 101,
ccb : 202 } } };
Note that underscore.js's extend-method does this in a one-liner:
_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
Similar to jQuery extend(), you have the same function in AngularJS:
// Merge the 'options' object into the 'settings' object
var settings = {validate: false, limit: 5, name: "foo"};
var options = {validate: true, name: "bar"};
angular.extend(settings, options);
I need to merge objects today, and this question (and answers) helped me a lot. I tried some of the answers, but none of them fit my needs, so I combined some of the answers, added something myself and came up with a new merge function. Here it is:
var merge = function() {
var obj = {},
i = 0,
il = arguments.length,
key;
for (; i < il; i++) {
for (key in arguments[i]) {
if (arguments[i].hasOwnProperty(key)) {
obj[key] = arguments[i][key];
}
}
}
return obj;
};
Some example usages:
var t1 = {
key1: 1,
key2: "test",
key3: [5, 2, 76, 21]
};
var t2 = {
key1: {
ik1: "hello",
ik2: "world",
ik3: 3
}
};
var t3 = {
key2: 3,
key3: {
t1: 1,
t2: 2,
t3: {
a1: 1,
a2: 3,
a4: [21, 3, 42, "asd"]
}
}
};
console.log(merge(t1, t2));
console.log(merge(t1, t3));
console.log(merge(t2, t3));
console.log(merge(t1, t2, t3));
console.log(merge({}, t1, { key1: 1 }));
You can use the object spread syntax to achieve this. It's a part of ES2018 and beyond.
const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { animal: 'dog' };
const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
The given solutions should be modified to check source.hasOwnProperty(property) in the for..in loops before assigning - otherwise, you end up copying the properties of the whole prototype chain, which is rarely desired...
Merge properties of N objects in one line of code
An Object.assign method is part of the ECMAScript 2015 (ES6) standard and does exactly what you need. (IE not supported)
var clone = Object.assign({}, obj);
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object.
Read more...
The polyfill to support older browsers:
if (!Object.assign) {
Object.defineProperty(Object, 'assign', {
enumerable: false,
configurable: true,
writable: true,
value: function(target) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert first argument to object');
}
var to = Object(target);
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
if (nextSource === undefined || nextSource === null) {
continue;
}
nextSource = Object(nextSource);
var keysArray = Object.keys(nextSource);
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
var nextKey = keysArray[nextIndex];
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
if (desc !== undefined && desc.enumerable) {
to[nextKey] = nextSource[nextKey];
}
}
}
return to;
}
});
}
The following two are probably a good starting point. lodash also has a customizer function for those special needs!
_.extend (http://underscorejs.org/#extend)
_.merge (https://lodash.com/docs#merge)
Here's my stab which
Supports deep merge
Does not mutate arguments
Takes any number of arguments
Does not extend the object prototype
Does not depend on another library (jQuery, MooTools, Underscore.js, etc.)
Includes check for hasOwnProperty
Is short :)
/*
Recursively merge properties and return new object
obj1 <- obj2 [ <- ... ]
*/
function merge () {
var dst = {}
,src
,p
,args = [].splice.call(arguments, 0)
;
while (args.length > 0) {
src = args.splice(0, 1)[0];
if (toString.call(src) == '[object Object]') {
for (p in src) {
if (src.hasOwnProperty(p)) {
if (toString.call(src[p]) == '[object Object]') {
dst[p] = merge(dst[p] || {}, src[p]);
} else {
dst[p] = src[p];
}
}
}
}
}
return dst;
}
Example:
a = {
"p1": "p1a",
"p2": [
"a",
"b",
"c"
],
"p3": true,
"p5": null,
"p6": {
"p61": "p61a",
"p62": "p62a",
"p63": [
"aa",
"bb",
"cc"
],
"p64": {
"p641": "p641a"
}
}
};
b = {
"p1": "p1b",
"p2": [
"d",
"e",
"f"
],
"p3": false,
"p4": true,
"p6": {
"p61": "p61b",
"p64": {
"p642": "p642b"
}
}
};
c = {
"p1": "p1c",
"p3": null,
"p6": {
"p62": "p62c",
"p64": {
"p643": "p641c"
}
}
};
d = merge(a, b, c);
/*
d = {
"p1": "p1c",
"p2": [
"d",
"e",
"f"
],
"p3": null,
"p5": null,
"p6": {
"p61": "p61b",
"p62": "p62c",
"p63": [
"aa",
"bb",
"cc"
],
"p64": {
"p641": "p641a",
"p642": "p642b",
"p643": "p641c"
}
},
"p4": true
};
*/
Just by the way, what you're all doing is overwriting properties, not merging...
This is how JavaScript objects area really merged: Only keys in the to object which are not objects themselves will be overwritten by from. Everything else will be really merged. Of course you can change this behaviour to not overwrite anything which exists like only if to[n] is undefined, etc...:
var realMerge = function (to, from) {
for (n in from) {
if (typeof to[n] != 'object') {
to[n] = from[n];
} else if (typeof from[n] == 'object') {
to[n] = realMerge(to[n], from[n]);
}
}
return to;
};
Usage:
var merged = realMerge(obj1, obj2);
Object.assign()
ECMAScript 2015 (ES6)
This is a new technology, part of the ECMAScript 2015 (ES6) standard.
This technology's specification has been finalized, but check the compatibility table for usage and implementation status in various browsers.
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed.
For not-too-complicated objects you could use JSON:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'chevy'}
var objMerge;
objMerge = JSON.stringify(obj1) + JSON.stringify(obj2);
// {"food": "pizza","car":"ford"}{"animal":"dog","car":"chevy"}
objMerge = objMerge.replace(/\}\{/, ","); // \_ replace with comma for valid JSON
objMerge = JSON.parse(objMerge); // { food: 'pizza', animal: 'dog', car: 'chevy'}
// Of same keys in both objects, the last object's value is retained_/
Mind you that in this example "}{" must not occur within a string!
There's a library called deepmerge on GitHub: That seems to be getting some traction. It's a standalone, available through both the npm and bower package managers.
I would be inclined to use or improve on this instead of copy-pasting code from answers.
The best way for you to do this is to add a proper property that is non-enumerable using Object.defineProperty.
This way you will still be able to iterate over your objects properties without having the newly created "extend" that you would get if you were to create the property with Object.prototype.extend.
Hopefully this helps:
Object.defineProperty(Object.prototype, "extend", {
enumerable: false,
value: function(from) {
var props = Object.getOwnPropertyNames(from);
var dest = this;
props.forEach(function(name) {
if (name in dest) {
var destination = Object.getOwnPropertyDescriptor(from, name);
Object.defineProperty(dest, name, destination);
}
});
return this;
}
});
Once you have that working, you can do:
var obj = {
name: 'stack',
finish: 'overflow'
}
var replacement = {
name: 'stock'
};
obj.extend(replacement);
I just wrote a blog post about it here: http://onemoredigit.com/post/1527191998/extending-objects-in-node-js
You can simply use jQuery extend
var obj1 = { val1: false, limit: 5, name: "foo" };
var obj2 = { val2: true, name: "bar" };
jQuery.extend(obj1, obj2);
Now obj1 contains all the values of obj1 and obj2
Prototype has this:
Object.extend = function(destination,source) {
for (var property in source)
destination[property] = source[property];
return destination;
}
obj1.extend(obj2) will do what you want.
Wow.. this is the first StackOverflow post I've seen with multiple pages. Apologies for adding another "answer"
ES5 & Earlier
This method is for ES5 & Earlier - there are plenty of other answers addressing ES6.
I did not see any "deep" object merging utilizing the arguments property. Here is my answer - compact & recursive, allowing unlimited object arguments to be passed:
function extend() {
for (var o = {}, i = 0; i < arguments.length; i++) {
// Uncomment to skip arguments that are not objects (to prevent errors)
// if (arguments[i].constructor !== Object) continue;
for (var k in arguments[i]) {
if (arguments[i].hasOwnProperty(k)) {
o[k] = arguments[i][k].constructor === Object
? extend(o[k] || {}, arguments[i][k])
: arguments[i][k];
}
}
}
return o;
}
Example
/**
* Extend objects
*/
function extend() {
for (var o = {}, i = 0; i < arguments.length; i++) {
for (var k in arguments[i]) {
if (arguments[i].hasOwnProperty(k)) {
o[k] = arguments[i][k].constructor === Object
? extend(o[k] || {}, arguments[i][k])
: arguments[i][k];
}
}
}
return o;
}
/**
* Example
*/
document.write(JSON.stringify(extend({
api: 1,
params: {
query: 'hello'
}
}, {
params: {
query: 'there'
}
})));
// outputs {"api": 1, "params": {"query": "there"}}
This answer is now but a drop in the ocean ...
Just if anyone is using Google Closure Library:
goog.require('goog.object');
var a = {'a': 1, 'b': 2};
var b = {'b': 3, 'c': 4};
goog.object.extend(a, b);
// Now object a == {'a': 1, 'b': 3, 'c': 4};
Similar helper function exists for array:
var a = [1, 2];
var b = [3, 4];
goog.array.extend(a, b); // Extends array 'a'
goog.array.concat(a, b); // Returns concatenation of array 'a' and 'b'
**Merging objects is simple using Object.assign or the spread ... operator **
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'BMW' }
var obj3 = {a: "A"}
var mergedObj = Object.assign(obj1,obj2,obj3)
// or using the Spread operator (...)
var mergedObj = {...obj1,...obj2,...obj3}
console.log(mergedObj);
The objects are merged from right to left, this means that objects which have identical properties as the objects to their right will be overriden.
In this example obj2.car overrides obj1.car
I extended David Coallier's method:
Added the possibility to merge multiple objects
Supports deep objects
override parameter (that's detected if the last parameter is a boolean)
If override is false, no property gets overridden but new properties will be added.
Usage:
obj.merge(merges... [, override]);
Here is my code:
Object.defineProperty(Object.prototype, "merge", {
enumerable: false,
value: function () {
var override = true,
dest = this,
len = arguments.length,
props, merge, i, from;
if (typeof(arguments[arguments.length - 1]) === "boolean") {
override = arguments[arguments.length - 1];
len = arguments.length - 1;
}
for (i = 0; i < len; i++) {
from = arguments[i];
if (from != null) {
Object.getOwnPropertyNames(from).forEach(function (name) {
var descriptor;
// nesting
if ((typeof(dest[name]) === "object" || typeof(dest[name]) === "undefined")
&& typeof(from[name]) === "object") {
// ensure proper types (Array rsp Object)
if (typeof(dest[name]) === "undefined") {
dest[name] = Array.isArray(from[name]) ? [] : {};
}
if (override) {
if (!Array.isArray(dest[name]) && Array.isArray(from[name])) {
dest[name] = [];
}
else if (Array.isArray(dest[name]) && !Array.isArray(from[name])) {
dest[name] = {};
}
}
dest[name].merge(from[name], override);
}
// flat properties
else if ((name in dest && override) || !(name in dest)) {
descriptor = Object.getOwnPropertyDescriptor(from, name);
if (descriptor.configurable) {
Object.defineProperty(dest, name, descriptor);
}
}
});
}
}
return this;
}
});
Examples and TestCases:
function clone (obj) {
return JSON.parse(JSON.stringify(obj));
}
var obj = {
name : "trick",
value : "value"
};
var mergeObj = {
name : "truck",
value2 : "value2"
};
var mergeObj2 = {
name : "track",
value : "mergeObj2",
value2 : "value2-mergeObj2",
value3 : "value3"
};
assertTrue("Standard", clone(obj).merge(mergeObj).equals({
name : "truck",
value : "value",
value2 : "value2"
}));
assertTrue("Standard no Override", clone(obj).merge(mergeObj, false).equals({
name : "trick",
value : "value",
value2 : "value2"
}));
assertTrue("Multiple", clone(obj).merge(mergeObj, mergeObj2).equals({
name : "track",
value : "mergeObj2",
value2 : "value2-mergeObj2",
value3 : "value3"
}));
assertTrue("Multiple no Override", clone(obj).merge(mergeObj, mergeObj2, false).equals({
name : "trick",
value : "value",
value2 : "value2",
value3 : "value3"
}));
var deep = {
first : {
name : "trick",
val : "value"
},
second : {
foo : "bar"
}
};
var deepMerge = {
first : {
name : "track",
anotherVal : "wohoo"
},
second : {
foo : "baz",
bar : "bam"
},
v : "on first layer"
};
assertTrue("Deep merges", clone(deep).merge(deepMerge).equals({
first : {
name : "track",
val : "value",
anotherVal : "wohoo"
},
second : {
foo : "baz",
bar : "bam"
},
v : "on first layer"
}));
assertTrue("Deep merges no override", clone(deep).merge(deepMerge, false).equals({
first : {
name : "trick",
val : "value",
anotherVal : "wohoo"
},
second : {
foo : "bar",
bar : "bam"
},
v : "on first layer"
}));
var obj1 = {a: 1, b: "hello"};
obj1.merge({c: 3});
assertTrue(obj1.equals({a: 1, b: "hello", c: 3}));
obj1.merge({a: 2, b: "mom", d: "new property"}, false);
assertTrue(obj1.equals({a: 1, b: "hello", c: 3, d: "new property"}));
var obj2 = {};
obj2.merge({a: 1}, {b: 2}, {a: 3});
assertTrue(obj2.equals({a: 3, b: 2}));
var a = [];
var b = [1, [2, 3], 4];
a.merge(b);
assertEquals(1, a[0]);
assertEquals([2, 3], a[1]);
assertEquals(4, a[2]);
var o1 = {};
var o2 = {a: 1, b: {c: 2}};
var o3 = {d: 3};
o1.merge(o2, o3);
assertTrue(o1.equals({a: 1, b: {c: 2}, d: 3}));
o1.b.c = 99;
assertTrue(o2.equals({a: 1, b: {c: 2}}));
// checking types with arrays and objects
var bo;
a = [];
bo = [1, {0:2, 1:3}, 4];
b = [1, [2, 3], 4];
a.merge(b);
assertTrue("Array stays Array?", Array.isArray(a[1]));
a = [];
a.merge(bo);
assertTrue("Object stays Object?", !Array.isArray(a[1]));
a = [];
a.merge(b);
a.merge(bo);
assertTrue("Object overrides Array", !Array.isArray(a[1]));
a = [];
a.merge(b);
a.merge(bo, false);
assertTrue("Object does not override Array", Array.isArray(a[1]));
a = [];
a.merge(bo);
a.merge(b);
assertTrue("Array overrides Object", Array.isArray(a[1]));
a = [];
a.merge(bo);
a.merge(b, false);
assertTrue("Array does not override Object", !Array.isArray(a[1]));
My equals method can be found here: Object comparison in JavaScript
In MooTools, there's Object.merge():
Object.merge(obj1, obj2);
var firstObject = {
key1 : 'value1',
key2 : 'value2'
};
var secondObject={
...firstObject,
key3 : 'value3',
key4 : 'value4',
key5 : 'value5'
}
console.log(firstObject);
console.log(secondObject);
In Ext JS 4 it can be done as follows:
var mergedObject = Ext.Object.merge(object1, object2)
// Or shorter:
var mergedObject2 = Ext.merge(object1, object2)
See merge( object ) : Object.
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
// result
result: {food: "pizza", car: "ford", animal: "dog"}
Using jQuery.extend() - Link
// Merge obj1 & obj2 to result
var result1 = $.extend( {}, obj1, obj2 );
Using _.merge() - Link
// Merge obj1 & obj2 to result
var result2 = _.merge( {}, obj1, obj2 );
Using _.extend() - Link
// Merge obj1 & obj2 to result
var result3 = _.extend( {}, obj1, obj2 );
Using Object.assign() ECMAScript 2015 (ES6) - Link
// Merge obj1 & obj2 to result
var result4 = Object.assign( {}, obj1, obj2 );
Output of all
obj1: { animal: 'dog' }
obj2: { food: 'pizza', car: 'ford' }
result1: {food: "pizza", car: "ford", animal: "dog"}
result2: {food: "pizza", car: "ford", animal: "dog"}
result3: {food: "pizza", car: "ford", animal: "dog"}
result4: {food: "pizza", car: "ford", animal: "dog"}
Based on Markus' and vsync' answer, this is an expanded version. The function takes any number of arguments. It can be used to set properties on DOM nodes and makes deep copies of values. However, the first argument is given by reference.
To detect a DOM node, the isDOMNode() function is used (see Stack Overflow question JavaScript isDOM — How do you check if a JavaScript Object is a DOM Object?)
It was tested in Opera 11, Firefox 6, Internet Explorer 8 and Google Chrome 16.
Code
function mergeRecursive() {
// _mergeRecursive does the actual job with two arguments.
var _mergeRecursive = function (dst, src) {
if (isDOMNode(src) || typeof src !== 'object' || src === null) {
return dst;
}
for (var p in src) {
if (!src.hasOwnProperty(p))
continue;
if (src[p] === undefined)
continue;
if ( typeof src[p] !== 'object' || src[p] === null) {
dst[p] = src[p];
} else if (typeof dst[p]!=='object' || dst[p] === null) {
dst[p] = _mergeRecursive(src[p].constructor===Array ? [] : {}, src[p]);
} else {
_mergeRecursive(dst[p], src[p]);
}
}
return dst;
}
// Loop through arguments and merge them into the first argument.
var out = arguments[0];
if (typeof out !== 'object' || out === null)
return out;
for (var i = 1, il = arguments.length; i < il; i++) {
_mergeRecursive(out, arguments[i]);
}
return out;
}
Some examples
Set innerHTML and style of a HTML Element
mergeRecursive(
document.getElementById('mydiv'),
{style: {border: '5px solid green', color: 'red'}},
{innerHTML: 'Hello world!'});
Merge arrays and objects. Note that undefined can be used to preserv values in the lefthand array/object.
o = mergeRecursive({a:'a'}, [1,2,3], [undefined, null, [30,31]], {a:undefined, b:'b'});
// o = {0:1, 1:null, 2:[30,31], a:'a', b:'b'}
Any argument not beeing a JavaScript object (including null) will be ignored. Except for the first argument, also DOM nodes are discarded. Beware that i.e. strings, created like new String() are in fact objects.
o = mergeRecursive({a:'a'}, 1, true, null, undefined, [1,2,3], 'bc', new String('de'));
// o = {0:'d', 1:'e', 2:3, a:'a'}
If you want to merge two objects into a new (without affecting any of the two) supply {} as first argument
var a={}, b={b:'abc'}, c={c:'cde'}, o;
o = mergeRecursive(a, b, c);
// o===a is true, o===b is false, o===c is false
Edit (by ReaperSoon):
To also merge arrays
function mergeRecursive(obj1, obj2) {
if (Array.isArray(obj2)) { return obj1.concat(obj2); }
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if ( obj2[p].constructor==Object ) {
obj1[p] = mergeRecursive(obj1[p], obj2[p]);
} else if (Array.isArray(obj2[p])) {
obj1[p] = obj1[p].concat(obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch(e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
It seems like this should be all you need:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
var obj3 = { ...obj1, ...obj2 }
After that obj3 should now have the following value:
{food: "pizza", car: "ford", animal: "dog"}
Try it out here:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
var obj3 = { ...obj1, ...obj2 }
console.log(obj3);
You should use lodash's defaultsDeep
_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }
I need to be able to merge two (very simple) JavaScript objects at runtime. For example I'd like to:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
obj1.merge(obj2);
//obj1 now has three properties: food, car, and animal
Is there a built in way to do this? I do not need recursion, and I do not need to merge functions, just methods on flat objects.
ECMAScript 2018 Standard Method
You would use object spread:
let merged = {...obj1, ...obj2};
merged is now the union of obj1 and obj2. Properties in obj2 will overwrite those in obj1.
/** There's no limit to the number of objects you can merge.
* Later properties overwrite earlier properties with the same name. */
const allRules = {...obj1, ...obj2, ...obj3};
Here is also the MDN documentation for this syntax. If you're using babel you'll need the #babel/plugin-proposal-object-rest-spread plugin for it to work (This plugin is included in #babel/preset-env, in ES2018).
ECMAScript 2015 (ES6) Standard Method
/* For the case in question, you would do: */
Object.assign(obj1, obj2);
/** There's no limit to the number of objects you can merge.
* All objects get merged into the first object.
* Only the object in the first argument is mutated and returned.
* Later properties overwrite earlier properties with the same name. */
const allRules = Object.assign({}, obj1, obj2, obj3, etc);
(see MDN JavaScript Reference)
Method for ES5 and Earlier
for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
Note that this will simply add all attributes of obj2 to obj1 which might not be what you want if you still want to use the unmodified obj1.
If you're using a framework that craps all over your prototypes then you have to get fancier with checks like hasOwnProperty, but that code will work for 99% of cases.
Example function:
/**
* Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
* #param obj1
* #param obj2
* #returns obj3 a new object based on obj1 and obj2
*/
function merge_options(obj1,obj2){
var obj3 = {};
for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
return obj3;
}
jQuery also has a utility for this: http://api.jquery.com/jQuery.extend/.
Taken from the jQuery documentation:
// Merge options object into settings object
var settings = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
jQuery.extend(settings, options);
// Now the content of settings object is the following:
// { validate: true, limit: 5, name: "bar" }
The above code will mutate the existing object named settings.
If you want to create a new object without modifying either argument, use this:
var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
/* Merge defaults and options, without modifying defaults */
var settings = $.extend({}, defaults, options);
// The content of settings variable is now the following:
// {validate: true, limit: 5, name: "bar"}
// The 'defaults' and 'options' variables remained the same.
The Harmony ECMAScript 2015 (ES6) specifies Object.assign which will do this.
Object.assign(obj1, obj2);
Current browser support is getting better, but if you're developing for browsers that don't have support, you can use a polyfill.
I googled for code to merge object properties and ended up here. However since there wasn't any code for recursive merge I wrote it myself. (Maybe jQuery extend is recursive BTW?) Anyhow, hopefully someone else will find it useful as well.
(Now the code does not use Object.prototype :)
Code
/*
* Recursively merge properties of two objects
*/
function MergeRecursive(obj1, obj2) {
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if ( obj2[p].constructor==Object ) {
obj1[p] = MergeRecursive(obj1[p], obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch(e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
An example
o1 = { a : 1,
b : 2,
c : {
ca : 1,
cb : 2,
cc : {
cca : 100,
ccb : 200 } } };
o2 = { a : 10,
c : {
ca : 10,
cb : 20,
cc : {
cca : 101,
ccb : 202 } } };
o3 = MergeRecursive(o1, o2);
Produces object o3 like
o3 = { a : 10,
b : 2,
c : {
ca : 10,
cb : 20,
cc : {
cca : 101,
ccb : 202 } } };
Note that underscore.js's extend-method does this in a one-liner:
_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
Similar to jQuery extend(), you have the same function in AngularJS:
// Merge the 'options' object into the 'settings' object
var settings = {validate: false, limit: 5, name: "foo"};
var options = {validate: true, name: "bar"};
angular.extend(settings, options);
I need to merge objects today, and this question (and answers) helped me a lot. I tried some of the answers, but none of them fit my needs, so I combined some of the answers, added something myself and came up with a new merge function. Here it is:
var merge = function() {
var obj = {},
i = 0,
il = arguments.length,
key;
for (; i < il; i++) {
for (key in arguments[i]) {
if (arguments[i].hasOwnProperty(key)) {
obj[key] = arguments[i][key];
}
}
}
return obj;
};
Some example usages:
var t1 = {
key1: 1,
key2: "test",
key3: [5, 2, 76, 21]
};
var t2 = {
key1: {
ik1: "hello",
ik2: "world",
ik3: 3
}
};
var t3 = {
key2: 3,
key3: {
t1: 1,
t2: 2,
t3: {
a1: 1,
a2: 3,
a4: [21, 3, 42, "asd"]
}
}
};
console.log(merge(t1, t2));
console.log(merge(t1, t3));
console.log(merge(t2, t3));
console.log(merge(t1, t2, t3));
console.log(merge({}, t1, { key1: 1 }));
You can use the object spread syntax to achieve this. It's a part of ES2018 and beyond.
const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { animal: 'dog' };
const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
The given solutions should be modified to check source.hasOwnProperty(property) in the for..in loops before assigning - otherwise, you end up copying the properties of the whole prototype chain, which is rarely desired...
Merge properties of N objects in one line of code
An Object.assign method is part of the ECMAScript 2015 (ES6) standard and does exactly what you need. (IE not supported)
var clone = Object.assign({}, obj);
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object.
Read more...
The polyfill to support older browsers:
if (!Object.assign) {
Object.defineProperty(Object, 'assign', {
enumerable: false,
configurable: true,
writable: true,
value: function(target) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert first argument to object');
}
var to = Object(target);
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
if (nextSource === undefined || nextSource === null) {
continue;
}
nextSource = Object(nextSource);
var keysArray = Object.keys(nextSource);
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
var nextKey = keysArray[nextIndex];
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
if (desc !== undefined && desc.enumerable) {
to[nextKey] = nextSource[nextKey];
}
}
}
return to;
}
});
}
The following two are probably a good starting point. lodash also has a customizer function for those special needs!
_.extend (http://underscorejs.org/#extend)
_.merge (https://lodash.com/docs#merge)
Here's my stab which
Supports deep merge
Does not mutate arguments
Takes any number of arguments
Does not extend the object prototype
Does not depend on another library (jQuery, MooTools, Underscore.js, etc.)
Includes check for hasOwnProperty
Is short :)
/*
Recursively merge properties and return new object
obj1 <- obj2 [ <- ... ]
*/
function merge () {
var dst = {}
,src
,p
,args = [].splice.call(arguments, 0)
;
while (args.length > 0) {
src = args.splice(0, 1)[0];
if (toString.call(src) == '[object Object]') {
for (p in src) {
if (src.hasOwnProperty(p)) {
if (toString.call(src[p]) == '[object Object]') {
dst[p] = merge(dst[p] || {}, src[p]);
} else {
dst[p] = src[p];
}
}
}
}
}
return dst;
}
Example:
a = {
"p1": "p1a",
"p2": [
"a",
"b",
"c"
],
"p3": true,
"p5": null,
"p6": {
"p61": "p61a",
"p62": "p62a",
"p63": [
"aa",
"bb",
"cc"
],
"p64": {
"p641": "p641a"
}
}
};
b = {
"p1": "p1b",
"p2": [
"d",
"e",
"f"
],
"p3": false,
"p4": true,
"p6": {
"p61": "p61b",
"p64": {
"p642": "p642b"
}
}
};
c = {
"p1": "p1c",
"p3": null,
"p6": {
"p62": "p62c",
"p64": {
"p643": "p641c"
}
}
};
d = merge(a, b, c);
/*
d = {
"p1": "p1c",
"p2": [
"d",
"e",
"f"
],
"p3": null,
"p5": null,
"p6": {
"p61": "p61b",
"p62": "p62c",
"p63": [
"aa",
"bb",
"cc"
],
"p64": {
"p641": "p641a",
"p642": "p642b",
"p643": "p641c"
}
},
"p4": true
};
*/
Just by the way, what you're all doing is overwriting properties, not merging...
This is how JavaScript objects area really merged: Only keys in the to object which are not objects themselves will be overwritten by from. Everything else will be really merged. Of course you can change this behaviour to not overwrite anything which exists like only if to[n] is undefined, etc...:
var realMerge = function (to, from) {
for (n in from) {
if (typeof to[n] != 'object') {
to[n] = from[n];
} else if (typeof from[n] == 'object') {
to[n] = realMerge(to[n], from[n]);
}
}
return to;
};
Usage:
var merged = realMerge(obj1, obj2);
Object.assign()
ECMAScript 2015 (ES6)
This is a new technology, part of the ECMAScript 2015 (ES6) standard.
This technology's specification has been finalized, but check the compatibility table for usage and implementation status in various browsers.
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed.
For not-too-complicated objects you could use JSON:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'chevy'}
var objMerge;
objMerge = JSON.stringify(obj1) + JSON.stringify(obj2);
// {"food": "pizza","car":"ford"}{"animal":"dog","car":"chevy"}
objMerge = objMerge.replace(/\}\{/, ","); // \_ replace with comma for valid JSON
objMerge = JSON.parse(objMerge); // { food: 'pizza', animal: 'dog', car: 'chevy'}
// Of same keys in both objects, the last object's value is retained_/
Mind you that in this example "}{" must not occur within a string!
There's a library called deepmerge on GitHub: That seems to be getting some traction. It's a standalone, available through both the npm and bower package managers.
I would be inclined to use or improve on this instead of copy-pasting code from answers.
The best way for you to do this is to add a proper property that is non-enumerable using Object.defineProperty.
This way you will still be able to iterate over your objects properties without having the newly created "extend" that you would get if you were to create the property with Object.prototype.extend.
Hopefully this helps:
Object.defineProperty(Object.prototype, "extend", {
enumerable: false,
value: function(from) {
var props = Object.getOwnPropertyNames(from);
var dest = this;
props.forEach(function(name) {
if (name in dest) {
var destination = Object.getOwnPropertyDescriptor(from, name);
Object.defineProperty(dest, name, destination);
}
});
return this;
}
});
Once you have that working, you can do:
var obj = {
name: 'stack',
finish: 'overflow'
}
var replacement = {
name: 'stock'
};
obj.extend(replacement);
I just wrote a blog post about it here: http://onemoredigit.com/post/1527191998/extending-objects-in-node-js
You can simply use jQuery extend
var obj1 = { val1: false, limit: 5, name: "foo" };
var obj2 = { val2: true, name: "bar" };
jQuery.extend(obj1, obj2);
Now obj1 contains all the values of obj1 and obj2
Prototype has this:
Object.extend = function(destination,source) {
for (var property in source)
destination[property] = source[property];
return destination;
}
obj1.extend(obj2) will do what you want.
Wow.. this is the first StackOverflow post I've seen with multiple pages. Apologies for adding another "answer"
ES5 & Earlier
This method is for ES5 & Earlier - there are plenty of other answers addressing ES6.
I did not see any "deep" object merging utilizing the arguments property. Here is my answer - compact & recursive, allowing unlimited object arguments to be passed:
function extend() {
for (var o = {}, i = 0; i < arguments.length; i++) {
// Uncomment to skip arguments that are not objects (to prevent errors)
// if (arguments[i].constructor !== Object) continue;
for (var k in arguments[i]) {
if (arguments[i].hasOwnProperty(k)) {
o[k] = arguments[i][k].constructor === Object
? extend(o[k] || {}, arguments[i][k])
: arguments[i][k];
}
}
}
return o;
}
Example
/**
* Extend objects
*/
function extend() {
for (var o = {}, i = 0; i < arguments.length; i++) {
for (var k in arguments[i]) {
if (arguments[i].hasOwnProperty(k)) {
o[k] = arguments[i][k].constructor === Object
? extend(o[k] || {}, arguments[i][k])
: arguments[i][k];
}
}
}
return o;
}
/**
* Example
*/
document.write(JSON.stringify(extend({
api: 1,
params: {
query: 'hello'
}
}, {
params: {
query: 'there'
}
})));
// outputs {"api": 1, "params": {"query": "there"}}
This answer is now but a drop in the ocean ...
Just if anyone is using Google Closure Library:
goog.require('goog.object');
var a = {'a': 1, 'b': 2};
var b = {'b': 3, 'c': 4};
goog.object.extend(a, b);
// Now object a == {'a': 1, 'b': 3, 'c': 4};
Similar helper function exists for array:
var a = [1, 2];
var b = [3, 4];
goog.array.extend(a, b); // Extends array 'a'
goog.array.concat(a, b); // Returns concatenation of array 'a' and 'b'
**Merging objects is simple using Object.assign or the spread ... operator **
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'BMW' }
var obj3 = {a: "A"}
var mergedObj = Object.assign(obj1,obj2,obj3)
// or using the Spread operator (...)
var mergedObj = {...obj1,...obj2,...obj3}
console.log(mergedObj);
The objects are merged from right to left, this means that objects which have identical properties as the objects to their right will be overriden.
In this example obj2.car overrides obj1.car
I extended David Coallier's method:
Added the possibility to merge multiple objects
Supports deep objects
override parameter (that's detected if the last parameter is a boolean)
If override is false, no property gets overridden but new properties will be added.
Usage:
obj.merge(merges... [, override]);
Here is my code:
Object.defineProperty(Object.prototype, "merge", {
enumerable: false,
value: function () {
var override = true,
dest = this,
len = arguments.length,
props, merge, i, from;
if (typeof(arguments[arguments.length - 1]) === "boolean") {
override = arguments[arguments.length - 1];
len = arguments.length - 1;
}
for (i = 0; i < len; i++) {
from = arguments[i];
if (from != null) {
Object.getOwnPropertyNames(from).forEach(function (name) {
var descriptor;
// nesting
if ((typeof(dest[name]) === "object" || typeof(dest[name]) === "undefined")
&& typeof(from[name]) === "object") {
// ensure proper types (Array rsp Object)
if (typeof(dest[name]) === "undefined") {
dest[name] = Array.isArray(from[name]) ? [] : {};
}
if (override) {
if (!Array.isArray(dest[name]) && Array.isArray(from[name])) {
dest[name] = [];
}
else if (Array.isArray(dest[name]) && !Array.isArray(from[name])) {
dest[name] = {};
}
}
dest[name].merge(from[name], override);
}
// flat properties
else if ((name in dest && override) || !(name in dest)) {
descriptor = Object.getOwnPropertyDescriptor(from, name);
if (descriptor.configurable) {
Object.defineProperty(dest, name, descriptor);
}
}
});
}
}
return this;
}
});
Examples and TestCases:
function clone (obj) {
return JSON.parse(JSON.stringify(obj));
}
var obj = {
name : "trick",
value : "value"
};
var mergeObj = {
name : "truck",
value2 : "value2"
};
var mergeObj2 = {
name : "track",
value : "mergeObj2",
value2 : "value2-mergeObj2",
value3 : "value3"
};
assertTrue("Standard", clone(obj).merge(mergeObj).equals({
name : "truck",
value : "value",
value2 : "value2"
}));
assertTrue("Standard no Override", clone(obj).merge(mergeObj, false).equals({
name : "trick",
value : "value",
value2 : "value2"
}));
assertTrue("Multiple", clone(obj).merge(mergeObj, mergeObj2).equals({
name : "track",
value : "mergeObj2",
value2 : "value2-mergeObj2",
value3 : "value3"
}));
assertTrue("Multiple no Override", clone(obj).merge(mergeObj, mergeObj2, false).equals({
name : "trick",
value : "value",
value2 : "value2",
value3 : "value3"
}));
var deep = {
first : {
name : "trick",
val : "value"
},
second : {
foo : "bar"
}
};
var deepMerge = {
first : {
name : "track",
anotherVal : "wohoo"
},
second : {
foo : "baz",
bar : "bam"
},
v : "on first layer"
};
assertTrue("Deep merges", clone(deep).merge(deepMerge).equals({
first : {
name : "track",
val : "value",
anotherVal : "wohoo"
},
second : {
foo : "baz",
bar : "bam"
},
v : "on first layer"
}));
assertTrue("Deep merges no override", clone(deep).merge(deepMerge, false).equals({
first : {
name : "trick",
val : "value",
anotherVal : "wohoo"
},
second : {
foo : "bar",
bar : "bam"
},
v : "on first layer"
}));
var obj1 = {a: 1, b: "hello"};
obj1.merge({c: 3});
assertTrue(obj1.equals({a: 1, b: "hello", c: 3}));
obj1.merge({a: 2, b: "mom", d: "new property"}, false);
assertTrue(obj1.equals({a: 1, b: "hello", c: 3, d: "new property"}));
var obj2 = {};
obj2.merge({a: 1}, {b: 2}, {a: 3});
assertTrue(obj2.equals({a: 3, b: 2}));
var a = [];
var b = [1, [2, 3], 4];
a.merge(b);
assertEquals(1, a[0]);
assertEquals([2, 3], a[1]);
assertEquals(4, a[2]);
var o1 = {};
var o2 = {a: 1, b: {c: 2}};
var o3 = {d: 3};
o1.merge(o2, o3);
assertTrue(o1.equals({a: 1, b: {c: 2}, d: 3}));
o1.b.c = 99;
assertTrue(o2.equals({a: 1, b: {c: 2}}));
// checking types with arrays and objects
var bo;
a = [];
bo = [1, {0:2, 1:3}, 4];
b = [1, [2, 3], 4];
a.merge(b);
assertTrue("Array stays Array?", Array.isArray(a[1]));
a = [];
a.merge(bo);
assertTrue("Object stays Object?", !Array.isArray(a[1]));
a = [];
a.merge(b);
a.merge(bo);
assertTrue("Object overrides Array", !Array.isArray(a[1]));
a = [];
a.merge(b);
a.merge(bo, false);
assertTrue("Object does not override Array", Array.isArray(a[1]));
a = [];
a.merge(bo);
a.merge(b);
assertTrue("Array overrides Object", Array.isArray(a[1]));
a = [];
a.merge(bo);
a.merge(b, false);
assertTrue("Array does not override Object", !Array.isArray(a[1]));
My equals method can be found here: Object comparison in JavaScript
In MooTools, there's Object.merge():
Object.merge(obj1, obj2);
var firstObject = {
key1 : 'value1',
key2 : 'value2'
};
var secondObject={
...firstObject,
key3 : 'value3',
key4 : 'value4',
key5 : 'value5'
}
console.log(firstObject);
console.log(secondObject);
In Ext JS 4 it can be done as follows:
var mergedObject = Ext.Object.merge(object1, object2)
// Or shorter:
var mergedObject2 = Ext.merge(object1, object2)
See merge( object ) : Object.
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
// result
result: {food: "pizza", car: "ford", animal: "dog"}
Using jQuery.extend() - Link
// Merge obj1 & obj2 to result
var result1 = $.extend( {}, obj1, obj2 );
Using _.merge() - Link
// Merge obj1 & obj2 to result
var result2 = _.merge( {}, obj1, obj2 );
Using _.extend() - Link
// Merge obj1 & obj2 to result
var result3 = _.extend( {}, obj1, obj2 );
Using Object.assign() ECMAScript 2015 (ES6) - Link
// Merge obj1 & obj2 to result
var result4 = Object.assign( {}, obj1, obj2 );
Output of all
obj1: { animal: 'dog' }
obj2: { food: 'pizza', car: 'ford' }
result1: {food: "pizza", car: "ford", animal: "dog"}
result2: {food: "pizza", car: "ford", animal: "dog"}
result3: {food: "pizza", car: "ford", animal: "dog"}
result4: {food: "pizza", car: "ford", animal: "dog"}
Based on Markus' and vsync' answer, this is an expanded version. The function takes any number of arguments. It can be used to set properties on DOM nodes and makes deep copies of values. However, the first argument is given by reference.
To detect a DOM node, the isDOMNode() function is used (see Stack Overflow question JavaScript isDOM — How do you check if a JavaScript Object is a DOM Object?)
It was tested in Opera 11, Firefox 6, Internet Explorer 8 and Google Chrome 16.
Code
function mergeRecursive() {
// _mergeRecursive does the actual job with two arguments.
var _mergeRecursive = function (dst, src) {
if (isDOMNode(src) || typeof src !== 'object' || src === null) {
return dst;
}
for (var p in src) {
if (!src.hasOwnProperty(p))
continue;
if (src[p] === undefined)
continue;
if ( typeof src[p] !== 'object' || src[p] === null) {
dst[p] = src[p];
} else if (typeof dst[p]!=='object' || dst[p] === null) {
dst[p] = _mergeRecursive(src[p].constructor===Array ? [] : {}, src[p]);
} else {
_mergeRecursive(dst[p], src[p]);
}
}
return dst;
}
// Loop through arguments and merge them into the first argument.
var out = arguments[0];
if (typeof out !== 'object' || out === null)
return out;
for (var i = 1, il = arguments.length; i < il; i++) {
_mergeRecursive(out, arguments[i]);
}
return out;
}
Some examples
Set innerHTML and style of a HTML Element
mergeRecursive(
document.getElementById('mydiv'),
{style: {border: '5px solid green', color: 'red'}},
{innerHTML: 'Hello world!'});
Merge arrays and objects. Note that undefined can be used to preserv values in the lefthand array/object.
o = mergeRecursive({a:'a'}, [1,2,3], [undefined, null, [30,31]], {a:undefined, b:'b'});
// o = {0:1, 1:null, 2:[30,31], a:'a', b:'b'}
Any argument not beeing a JavaScript object (including null) will be ignored. Except for the first argument, also DOM nodes are discarded. Beware that i.e. strings, created like new String() are in fact objects.
o = mergeRecursive({a:'a'}, 1, true, null, undefined, [1,2,3], 'bc', new String('de'));
// o = {0:'d', 1:'e', 2:3, a:'a'}
If you want to merge two objects into a new (without affecting any of the two) supply {} as first argument
var a={}, b={b:'abc'}, c={c:'cde'}, o;
o = mergeRecursive(a, b, c);
// o===a is true, o===b is false, o===c is false
Edit (by ReaperSoon):
To also merge arrays
function mergeRecursive(obj1, obj2) {
if (Array.isArray(obj2)) { return obj1.concat(obj2); }
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if ( obj2[p].constructor==Object ) {
obj1[p] = mergeRecursive(obj1[p], obj2[p]);
} else if (Array.isArray(obj2[p])) {
obj1[p] = obj1[p].concat(obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch(e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
It seems like this should be all you need:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
var obj3 = { ...obj1, ...obj2 }
After that obj3 should now have the following value:
{food: "pizza", car: "ford", animal: "dog"}
Try it out here:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
var obj3 = { ...obj1, ...obj2 }
console.log(obj3);
You should use lodash's defaultsDeep
_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }
This question already has answers here:
Group array items using object
(19 answers)
Closed 4 years ago.
If I have two objects:
const obj1 = {
"1,1" : "hello",
}
and
const obj2 = {
"1,1" : "hi",
}
what would be the easiest way to merge them into:
obj3 = {
"1,1": ["hello", "hi"],
}
can i use the spread operator here? thanks!
An alternative is using the function reduce.
const obj1 = {"1,1" : "hello"},
obj2 = {"1,1" : "hi"},
obj3 = [obj1, obj2].reduce((a, c) => {
Object.keys(c).forEach(k => (a[k] || (a[k] = [])).push(c[k]));
return a;
}, {});
console.log(obj3);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var obj1 = {
a: 1,
b: 2
};
var obj2 = {
a: 12,
c: 20
};
console.log(merge(obj1, obj2));
function merge(obj1, obj2) {
var obj3 = {};
Object.keys(obj1).forEach(function(key) {
pushIntoObj3(key, obj1[key]);
});
Object.keys(obj2).forEach(function(key) {
pushIntoObj3(key, obj2[key]);
});
function pushIntoObj3(key, val) {
if (!obj3[key]) {
obj3[key] = [];
}
obj3[key].push(val);
}
return obj3;
}
OUTPUT :
{
"a": [ 1, 12 ],
"b": [ 2 ],
"c": [ 20 ]
}
a simple way to do this would be to use the internal for (.. in ...) of javascript :
e.g.
obj1 = {1 : 2};
obj2 = {1 : 3};
obj3 = {};
for (element1 in obj1) {
for (element2 in obj2) {
if (element1 == element2) {
obj3[element1] = [];
obj3[element1].push(obj1[element1]);
obj3[element1].push(obj2[element2]);
}
}
}
//result : obj3 = {1 : [2,3]}
but then what if obj1 = {"1,1" : 2, 1.1 : 3} or obj1 = {"1,1" : [1,2,3,4]} ? You really need to "well define" your requirement, but this should be a pretty good start.
I need to be able to merge two (very simple) JavaScript objects at runtime. For example I'd like to:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
obj1.merge(obj2);
//obj1 now has three properties: food, car, and animal
Is there a built in way to do this? I do not need recursion, and I do not need to merge functions, just methods on flat objects.
ECMAScript 2018 Standard Method
You would use object spread:
let merged = {...obj1, ...obj2};
merged is now the union of obj1 and obj2. Properties in obj2 will overwrite those in obj1.
/** There's no limit to the number of objects you can merge.
* Later properties overwrite earlier properties with the same name. */
const allRules = {...obj1, ...obj2, ...obj3};
Here is also the MDN documentation for this syntax. If you're using babel you'll need the #babel/plugin-proposal-object-rest-spread plugin for it to work (This plugin is included in #babel/preset-env, in ES2018).
ECMAScript 2015 (ES6) Standard Method
/* For the case in question, you would do: */
Object.assign(obj1, obj2);
/** There's no limit to the number of objects you can merge.
* All objects get merged into the first object.
* Only the object in the first argument is mutated and returned.
* Later properties overwrite earlier properties with the same name. */
const allRules = Object.assign({}, obj1, obj2, obj3, etc);
(see MDN JavaScript Reference)
Method for ES5 and Earlier
for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
Note that this will simply add all attributes of obj2 to obj1 which might not be what you want if you still want to use the unmodified obj1.
If you're using a framework that craps all over your prototypes then you have to get fancier with checks like hasOwnProperty, but that code will work for 99% of cases.
Example function:
/**
* Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
* #param obj1
* #param obj2
* #returns obj3 a new object based on obj1 and obj2
*/
function merge_options(obj1,obj2){
var obj3 = {};
for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
return obj3;
}
jQuery also has a utility for this: http://api.jquery.com/jQuery.extend/.
Taken from the jQuery documentation:
// Merge options object into settings object
var settings = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
jQuery.extend(settings, options);
// Now the content of settings object is the following:
// { validate: true, limit: 5, name: "bar" }
The above code will mutate the existing object named settings.
If you want to create a new object without modifying either argument, use this:
var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
/* Merge defaults and options, without modifying defaults */
var settings = $.extend({}, defaults, options);
// The content of settings variable is now the following:
// {validate: true, limit: 5, name: "bar"}
// The 'defaults' and 'options' variables remained the same.
The Harmony ECMAScript 2015 (ES6) specifies Object.assign which will do this.
Object.assign(obj1, obj2);
Current browser support is getting better, but if you're developing for browsers that don't have support, you can use a polyfill.
I googled for code to merge object properties and ended up here. However since there wasn't any code for recursive merge I wrote it myself. (Maybe jQuery extend is recursive BTW?) Anyhow, hopefully someone else will find it useful as well.
(Now the code does not use Object.prototype :)
Code
/*
* Recursively merge properties of two objects
*/
function MergeRecursive(obj1, obj2) {
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if ( obj2[p].constructor==Object ) {
obj1[p] = MergeRecursive(obj1[p], obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch(e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
An example
o1 = { a : 1,
b : 2,
c : {
ca : 1,
cb : 2,
cc : {
cca : 100,
ccb : 200 } } };
o2 = { a : 10,
c : {
ca : 10,
cb : 20,
cc : {
cca : 101,
ccb : 202 } } };
o3 = MergeRecursive(o1, o2);
Produces object o3 like
o3 = { a : 10,
b : 2,
c : {
ca : 10,
cb : 20,
cc : {
cca : 101,
ccb : 202 } } };
Note that underscore.js's extend-method does this in a one-liner:
_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
Similar to jQuery extend(), you have the same function in AngularJS:
// Merge the 'options' object into the 'settings' object
var settings = {validate: false, limit: 5, name: "foo"};
var options = {validate: true, name: "bar"};
angular.extend(settings, options);
I need to merge objects today, and this question (and answers) helped me a lot. I tried some of the answers, but none of them fit my needs, so I combined some of the answers, added something myself and came up with a new merge function. Here it is:
var merge = function() {
var obj = {},
i = 0,
il = arguments.length,
key;
for (; i < il; i++) {
for (key in arguments[i]) {
if (arguments[i].hasOwnProperty(key)) {
obj[key] = arguments[i][key];
}
}
}
return obj;
};
Some example usages:
var t1 = {
key1: 1,
key2: "test",
key3: [5, 2, 76, 21]
};
var t2 = {
key1: {
ik1: "hello",
ik2: "world",
ik3: 3
}
};
var t3 = {
key2: 3,
key3: {
t1: 1,
t2: 2,
t3: {
a1: 1,
a2: 3,
a4: [21, 3, 42, "asd"]
}
}
};
console.log(merge(t1, t2));
console.log(merge(t1, t3));
console.log(merge(t2, t3));
console.log(merge(t1, t2, t3));
console.log(merge({}, t1, { key1: 1 }));
You can use the object spread syntax to achieve this. It's a part of ES2018 and beyond.
const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { animal: 'dog' };
const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
The given solutions should be modified to check source.hasOwnProperty(property) in the for..in loops before assigning - otherwise, you end up copying the properties of the whole prototype chain, which is rarely desired...
Merge properties of N objects in one line of code
An Object.assign method is part of the ECMAScript 2015 (ES6) standard and does exactly what you need. (IE not supported)
var clone = Object.assign({}, obj);
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object.
Read more...
The polyfill to support older browsers:
if (!Object.assign) {
Object.defineProperty(Object, 'assign', {
enumerable: false,
configurable: true,
writable: true,
value: function(target) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert first argument to object');
}
var to = Object(target);
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
if (nextSource === undefined || nextSource === null) {
continue;
}
nextSource = Object(nextSource);
var keysArray = Object.keys(nextSource);
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
var nextKey = keysArray[nextIndex];
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
if (desc !== undefined && desc.enumerable) {
to[nextKey] = nextSource[nextKey];
}
}
}
return to;
}
});
}
The following two are probably a good starting point. lodash also has a customizer function for those special needs!
_.extend (http://underscorejs.org/#extend)
_.merge (https://lodash.com/docs#merge)
Here's my stab which
Supports deep merge
Does not mutate arguments
Takes any number of arguments
Does not extend the object prototype
Does not depend on another library (jQuery, MooTools, Underscore.js, etc.)
Includes check for hasOwnProperty
Is short :)
/*
Recursively merge properties and return new object
obj1 <- obj2 [ <- ... ]
*/
function merge () {
var dst = {}
,src
,p
,args = [].splice.call(arguments, 0)
;
while (args.length > 0) {
src = args.splice(0, 1)[0];
if (toString.call(src) == '[object Object]') {
for (p in src) {
if (src.hasOwnProperty(p)) {
if (toString.call(src[p]) == '[object Object]') {
dst[p] = merge(dst[p] || {}, src[p]);
} else {
dst[p] = src[p];
}
}
}
}
}
return dst;
}
Example:
a = {
"p1": "p1a",
"p2": [
"a",
"b",
"c"
],
"p3": true,
"p5": null,
"p6": {
"p61": "p61a",
"p62": "p62a",
"p63": [
"aa",
"bb",
"cc"
],
"p64": {
"p641": "p641a"
}
}
};
b = {
"p1": "p1b",
"p2": [
"d",
"e",
"f"
],
"p3": false,
"p4": true,
"p6": {
"p61": "p61b",
"p64": {
"p642": "p642b"
}
}
};
c = {
"p1": "p1c",
"p3": null,
"p6": {
"p62": "p62c",
"p64": {
"p643": "p641c"
}
}
};
d = merge(a, b, c);
/*
d = {
"p1": "p1c",
"p2": [
"d",
"e",
"f"
],
"p3": null,
"p5": null,
"p6": {
"p61": "p61b",
"p62": "p62c",
"p63": [
"aa",
"bb",
"cc"
],
"p64": {
"p641": "p641a",
"p642": "p642b",
"p643": "p641c"
}
},
"p4": true
};
*/
Just by the way, what you're all doing is overwriting properties, not merging...
This is how JavaScript objects area really merged: Only keys in the to object which are not objects themselves will be overwritten by from. Everything else will be really merged. Of course you can change this behaviour to not overwrite anything which exists like only if to[n] is undefined, etc...:
var realMerge = function (to, from) {
for (n in from) {
if (typeof to[n] != 'object') {
to[n] = from[n];
} else if (typeof from[n] == 'object') {
to[n] = realMerge(to[n], from[n]);
}
}
return to;
};
Usage:
var merged = realMerge(obj1, obj2);
Object.assign()
ECMAScript 2015 (ES6)
This is a new technology, part of the ECMAScript 2015 (ES6) standard.
This technology's specification has been finalized, but check the compatibility table for usage and implementation status in various browsers.
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed.
For not-too-complicated objects you could use JSON:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'chevy'}
var objMerge;
objMerge = JSON.stringify(obj1) + JSON.stringify(obj2);
// {"food": "pizza","car":"ford"}{"animal":"dog","car":"chevy"}
objMerge = objMerge.replace(/\}\{/, ","); // \_ replace with comma for valid JSON
objMerge = JSON.parse(objMerge); // { food: 'pizza', animal: 'dog', car: 'chevy'}
// Of same keys in both objects, the last object's value is retained_/
Mind you that in this example "}{" must not occur within a string!
There's a library called deepmerge on GitHub: That seems to be getting some traction. It's a standalone, available through both the npm and bower package managers.
I would be inclined to use or improve on this instead of copy-pasting code from answers.
The best way for you to do this is to add a proper property that is non-enumerable using Object.defineProperty.
This way you will still be able to iterate over your objects properties without having the newly created "extend" that you would get if you were to create the property with Object.prototype.extend.
Hopefully this helps:
Object.defineProperty(Object.prototype, "extend", {
enumerable: false,
value: function(from) {
var props = Object.getOwnPropertyNames(from);
var dest = this;
props.forEach(function(name) {
if (name in dest) {
var destination = Object.getOwnPropertyDescriptor(from, name);
Object.defineProperty(dest, name, destination);
}
});
return this;
}
});
Once you have that working, you can do:
var obj = {
name: 'stack',
finish: 'overflow'
}
var replacement = {
name: 'stock'
};
obj.extend(replacement);
I just wrote a blog post about it here: http://onemoredigit.com/post/1527191998/extending-objects-in-node-js
You can simply use jQuery extend
var obj1 = { val1: false, limit: 5, name: "foo" };
var obj2 = { val2: true, name: "bar" };
jQuery.extend(obj1, obj2);
Now obj1 contains all the values of obj1 and obj2
Prototype has this:
Object.extend = function(destination,source) {
for (var property in source)
destination[property] = source[property];
return destination;
}
obj1.extend(obj2) will do what you want.
Wow.. this is the first StackOverflow post I've seen with multiple pages. Apologies for adding another "answer"
ES5 & Earlier
This method is for ES5 & Earlier - there are plenty of other answers addressing ES6.
I did not see any "deep" object merging utilizing the arguments property. Here is my answer - compact & recursive, allowing unlimited object arguments to be passed:
function extend() {
for (var o = {}, i = 0; i < arguments.length; i++) {
// Uncomment to skip arguments that are not objects (to prevent errors)
// if (arguments[i].constructor !== Object) continue;
for (var k in arguments[i]) {
if (arguments[i].hasOwnProperty(k)) {
o[k] = arguments[i][k].constructor === Object
? extend(o[k] || {}, arguments[i][k])
: arguments[i][k];
}
}
}
return o;
}
Example
/**
* Extend objects
*/
function extend() {
for (var o = {}, i = 0; i < arguments.length; i++) {
for (var k in arguments[i]) {
if (arguments[i].hasOwnProperty(k)) {
o[k] = arguments[i][k].constructor === Object
? extend(o[k] || {}, arguments[i][k])
: arguments[i][k];
}
}
}
return o;
}
/**
* Example
*/
document.write(JSON.stringify(extend({
api: 1,
params: {
query: 'hello'
}
}, {
params: {
query: 'there'
}
})));
// outputs {"api": 1, "params": {"query": "there"}}
This answer is now but a drop in the ocean ...
Just if anyone is using Google Closure Library:
goog.require('goog.object');
var a = {'a': 1, 'b': 2};
var b = {'b': 3, 'c': 4};
goog.object.extend(a, b);
// Now object a == {'a': 1, 'b': 3, 'c': 4};
Similar helper function exists for array:
var a = [1, 2];
var b = [3, 4];
goog.array.extend(a, b); // Extends array 'a'
goog.array.concat(a, b); // Returns concatenation of array 'a' and 'b'
**Merging objects is simple using Object.assign or the spread ... operator **
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'BMW' }
var obj3 = {a: "A"}
var mergedObj = Object.assign(obj1,obj2,obj3)
// or using the Spread operator (...)
var mergedObj = {...obj1,...obj2,...obj3}
console.log(mergedObj);
The objects are merged from right to left, this means that objects which have identical properties as the objects to their right will be overriden.
In this example obj2.car overrides obj1.car
I extended David Coallier's method:
Added the possibility to merge multiple objects
Supports deep objects
override parameter (that's detected if the last parameter is a boolean)
If override is false, no property gets overridden but new properties will be added.
Usage:
obj.merge(merges... [, override]);
Here is my code:
Object.defineProperty(Object.prototype, "merge", {
enumerable: false,
value: function () {
var override = true,
dest = this,
len = arguments.length,
props, merge, i, from;
if (typeof(arguments[arguments.length - 1]) === "boolean") {
override = arguments[arguments.length - 1];
len = arguments.length - 1;
}
for (i = 0; i < len; i++) {
from = arguments[i];
if (from != null) {
Object.getOwnPropertyNames(from).forEach(function (name) {
var descriptor;
// nesting
if ((typeof(dest[name]) === "object" || typeof(dest[name]) === "undefined")
&& typeof(from[name]) === "object") {
// ensure proper types (Array rsp Object)
if (typeof(dest[name]) === "undefined") {
dest[name] = Array.isArray(from[name]) ? [] : {};
}
if (override) {
if (!Array.isArray(dest[name]) && Array.isArray(from[name])) {
dest[name] = [];
}
else if (Array.isArray(dest[name]) && !Array.isArray(from[name])) {
dest[name] = {};
}
}
dest[name].merge(from[name], override);
}
// flat properties
else if ((name in dest && override) || !(name in dest)) {
descriptor = Object.getOwnPropertyDescriptor(from, name);
if (descriptor.configurable) {
Object.defineProperty(dest, name, descriptor);
}
}
});
}
}
return this;
}
});
Examples and TestCases:
function clone (obj) {
return JSON.parse(JSON.stringify(obj));
}
var obj = {
name : "trick",
value : "value"
};
var mergeObj = {
name : "truck",
value2 : "value2"
};
var mergeObj2 = {
name : "track",
value : "mergeObj2",
value2 : "value2-mergeObj2",
value3 : "value3"
};
assertTrue("Standard", clone(obj).merge(mergeObj).equals({
name : "truck",
value : "value",
value2 : "value2"
}));
assertTrue("Standard no Override", clone(obj).merge(mergeObj, false).equals({
name : "trick",
value : "value",
value2 : "value2"
}));
assertTrue("Multiple", clone(obj).merge(mergeObj, mergeObj2).equals({
name : "track",
value : "mergeObj2",
value2 : "value2-mergeObj2",
value3 : "value3"
}));
assertTrue("Multiple no Override", clone(obj).merge(mergeObj, mergeObj2, false).equals({
name : "trick",
value : "value",
value2 : "value2",
value3 : "value3"
}));
var deep = {
first : {
name : "trick",
val : "value"
},
second : {
foo : "bar"
}
};
var deepMerge = {
first : {
name : "track",
anotherVal : "wohoo"
},
second : {
foo : "baz",
bar : "bam"
},
v : "on first layer"
};
assertTrue("Deep merges", clone(deep).merge(deepMerge).equals({
first : {
name : "track",
val : "value",
anotherVal : "wohoo"
},
second : {
foo : "baz",
bar : "bam"
},
v : "on first layer"
}));
assertTrue("Deep merges no override", clone(deep).merge(deepMerge, false).equals({
first : {
name : "trick",
val : "value",
anotherVal : "wohoo"
},
second : {
foo : "bar",
bar : "bam"
},
v : "on first layer"
}));
var obj1 = {a: 1, b: "hello"};
obj1.merge({c: 3});
assertTrue(obj1.equals({a: 1, b: "hello", c: 3}));
obj1.merge({a: 2, b: "mom", d: "new property"}, false);
assertTrue(obj1.equals({a: 1, b: "hello", c: 3, d: "new property"}));
var obj2 = {};
obj2.merge({a: 1}, {b: 2}, {a: 3});
assertTrue(obj2.equals({a: 3, b: 2}));
var a = [];
var b = [1, [2, 3], 4];
a.merge(b);
assertEquals(1, a[0]);
assertEquals([2, 3], a[1]);
assertEquals(4, a[2]);
var o1 = {};
var o2 = {a: 1, b: {c: 2}};
var o3 = {d: 3};
o1.merge(o2, o3);
assertTrue(o1.equals({a: 1, b: {c: 2}, d: 3}));
o1.b.c = 99;
assertTrue(o2.equals({a: 1, b: {c: 2}}));
// checking types with arrays and objects
var bo;
a = [];
bo = [1, {0:2, 1:3}, 4];
b = [1, [2, 3], 4];
a.merge(b);
assertTrue("Array stays Array?", Array.isArray(a[1]));
a = [];
a.merge(bo);
assertTrue("Object stays Object?", !Array.isArray(a[1]));
a = [];
a.merge(b);
a.merge(bo);
assertTrue("Object overrides Array", !Array.isArray(a[1]));
a = [];
a.merge(b);
a.merge(bo, false);
assertTrue("Object does not override Array", Array.isArray(a[1]));
a = [];
a.merge(bo);
a.merge(b);
assertTrue("Array overrides Object", Array.isArray(a[1]));
a = [];
a.merge(bo);
a.merge(b, false);
assertTrue("Array does not override Object", !Array.isArray(a[1]));
My equals method can be found here: Object comparison in JavaScript
In MooTools, there's Object.merge():
Object.merge(obj1, obj2);
var firstObject = {
key1 : 'value1',
key2 : 'value2'
};
var secondObject={
...firstObject,
key3 : 'value3',
key4 : 'value4',
key5 : 'value5'
}
console.log(firstObject);
console.log(secondObject);
In Ext JS 4 it can be done as follows:
var mergedObject = Ext.Object.merge(object1, object2)
// Or shorter:
var mergedObject2 = Ext.merge(object1, object2)
See merge( object ) : Object.
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
// result
result: {food: "pizza", car: "ford", animal: "dog"}
Using jQuery.extend() - Link
// Merge obj1 & obj2 to result
var result1 = $.extend( {}, obj1, obj2 );
Using _.merge() - Link
// Merge obj1 & obj2 to result
var result2 = _.merge( {}, obj1, obj2 );
Using _.extend() - Link
// Merge obj1 & obj2 to result
var result3 = _.extend( {}, obj1, obj2 );
Using Object.assign() ECMAScript 2015 (ES6) - Link
// Merge obj1 & obj2 to result
var result4 = Object.assign( {}, obj1, obj2 );
Output of all
obj1: { animal: 'dog' }
obj2: { food: 'pizza', car: 'ford' }
result1: {food: "pizza", car: "ford", animal: "dog"}
result2: {food: "pizza", car: "ford", animal: "dog"}
result3: {food: "pizza", car: "ford", animal: "dog"}
result4: {food: "pizza", car: "ford", animal: "dog"}
Based on Markus' and vsync' answer, this is an expanded version. The function takes any number of arguments. It can be used to set properties on DOM nodes and makes deep copies of values. However, the first argument is given by reference.
To detect a DOM node, the isDOMNode() function is used (see Stack Overflow question JavaScript isDOM — How do you check if a JavaScript Object is a DOM Object?)
It was tested in Opera 11, Firefox 6, Internet Explorer 8 and Google Chrome 16.
Code
function mergeRecursive() {
// _mergeRecursive does the actual job with two arguments.
var _mergeRecursive = function (dst, src) {
if (isDOMNode(src) || typeof src !== 'object' || src === null) {
return dst;
}
for (var p in src) {
if (!src.hasOwnProperty(p))
continue;
if (src[p] === undefined)
continue;
if ( typeof src[p] !== 'object' || src[p] === null) {
dst[p] = src[p];
} else if (typeof dst[p]!=='object' || dst[p] === null) {
dst[p] = _mergeRecursive(src[p].constructor===Array ? [] : {}, src[p]);
} else {
_mergeRecursive(dst[p], src[p]);
}
}
return dst;
}
// Loop through arguments and merge them into the first argument.
var out = arguments[0];
if (typeof out !== 'object' || out === null)
return out;
for (var i = 1, il = arguments.length; i < il; i++) {
_mergeRecursive(out, arguments[i]);
}
return out;
}
Some examples
Set innerHTML and style of a HTML Element
mergeRecursive(
document.getElementById('mydiv'),
{style: {border: '5px solid green', color: 'red'}},
{innerHTML: 'Hello world!'});
Merge arrays and objects. Note that undefined can be used to preserv values in the lefthand array/object.
o = mergeRecursive({a:'a'}, [1,2,3], [undefined, null, [30,31]], {a:undefined, b:'b'});
// o = {0:1, 1:null, 2:[30,31], a:'a', b:'b'}
Any argument not beeing a JavaScript object (including null) will be ignored. Except for the first argument, also DOM nodes are discarded. Beware that i.e. strings, created like new String() are in fact objects.
o = mergeRecursive({a:'a'}, 1, true, null, undefined, [1,2,3], 'bc', new String('de'));
// o = {0:'d', 1:'e', 2:3, a:'a'}
If you want to merge two objects into a new (without affecting any of the two) supply {} as first argument
var a={}, b={b:'abc'}, c={c:'cde'}, o;
o = mergeRecursive(a, b, c);
// o===a is true, o===b is false, o===c is false
Edit (by ReaperSoon):
To also merge arrays
function mergeRecursive(obj1, obj2) {
if (Array.isArray(obj2)) { return obj1.concat(obj2); }
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if ( obj2[p].constructor==Object ) {
obj1[p] = mergeRecursive(obj1[p], obj2[p]);
} else if (Array.isArray(obj2[p])) {
obj1[p] = obj1[p].concat(obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch(e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
It seems like this should be all you need:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
var obj3 = { ...obj1, ...obj2 }
After that obj3 should now have the following value:
{food: "pizza", car: "ford", animal: "dog"}
Try it out here:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
var obj3 = { ...obj1, ...obj2 }
console.log(obj3);
You should use lodash's defaultsDeep
_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }