Combine Javascript Objects? [duplicate] - javascript

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 } }

Related

How to update all matching keys of an object with another [duplicate]

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 } }

Simple push array JS [duplicate]

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 } }

Producing a customized object in Javascript [duplicate]

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 } }

Return all properties in JS object to "empty" state

I wonder if there's a utility function in any framework like jQuery to truncate a JS object (there is more than one possible result, not sure what is the most useful yet):
{ // original object
foo: "bar",
arr: [1, 2, 3],
sub: {a: 4, b: 5, subsub: {c: 6}} }
{ // truncated, variant 1
foo: "",
arr: [],
sub: {} }
{ // truncated, variant 2
foo: "",
arr: [],
sub: {subsub: {}} }
{ // truncated, variant 3
foo: "",
arr: [],
sub: {a: 0, b: 0, subsub: {c: 0}} }
If no, is there a solution more clever than to recursively iterate over all properties, check types and remove / reset if necessary?
Call the constructor for each property to create an empty object of the same type.
for (var k in obj) {
obj[k] = obj[k] && obj[k].constructor();
}
This will also return numbers to 0, booleans to false, dates to now, and regexps to empty (but NaNs remain NaN).
To do this recursively, retaining object-valued properties but emptying them out too (variant 3):
function truncate(obj) {
for (var k in obj) {
var ctor = obj[k] && obj[k].constructor;
if (ctor === Object) truncate(obj[k]);
else if (ctor) obj[k] = ctor();
}
}
To eliminate numbers (variant 2), add a check:
function truncate(obj) {
for (var k in obj) {
var ctor = obj[k] && obj[k].constructor;
if (ctor === Object) truncate(obj[k]);
else if (ctor === Number) delete obj[k];
else if (ctor) obj[k] = ctor();
}
}
You may be looking for OMIT, part of underscore.js.
omit_.omit(object, *keys) Return a copy of the object, filtered to
omit the blacklisted keys (or array of keys). Alternatively accepts a
predicate indicating which keys to omit.
_.omit({name: 'moe', age: 50, userid: 'moe1'}, 'userid');
=> {name: 'moe', age: 50}
_.omit({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) { return _.isNumber(value); });
=> {name: 'moe', userid: 'moe1'}
Object.prototype.clear=function(){
for (prop in this){
if (typeof this[prop]==='string') this[prop]='';
else if (this[prop] instanceof Array) this[prop]=[];
else{
this[prop]={}//variant 1
}
}
return this;
}
.
var obj={
foo:"bar",
arr:[1,2,3],
sub:{b:4,c:5,subsub:{e:6}}
}
obj.clear()//returns {foo:"",arr:[],sub:{}}

How to concatenate properties from multiple JavaScript objects

I am looking for the best way to "add" multiple JavaScript objects (associative arrays).
For example, given:
a = { "one" : 1, "two" : 2 };
b = { "three" : 3 };
c = { "four" : 4, "five" : 5 };
what is the best way to compute:
{ "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }
ECMAscript 6 introduced Object.assign() to achieve this natively in Javascript.
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.
MDN documentation on Object.assign()
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 }
Object.assign is supported in many modern browsers but not yet all of them. Use a transpiler like Babel and Traceur to generate backwards-compatible ES5 JavaScript.
ECMAScript 6 has spread syntax. And now you can do this:
const obj1 = { 1: 11, 2: 22 };
const obj2 = { 3: 33, 4: 44 };
const obj3 = { ...obj1, ...obj2 };
console.log(obj3); // {1: 11, 2: 22, 3: 33, 4: 44}
This should do it:
function collect() {
var ret = {};
var len = arguments.length;
for (var i = 0; i < len; i++) {
for (p in arguments[i]) {
if (arguments[i].hasOwnProperty(p)) {
ret[p] = arguments[i][p];
}
}
}
return ret;
}
let a = { "one" : 1, "two" : 2 };
let b = { "three" : 3 };
let c = { "four" : 4, "five" : 5 };
let d = collect(a, b, c);
console.log(d);
Output:
{
"one": 1,
"two": 2,
"three": 3,
"four": 4,
"five": 5
}
You could use jquery's $.extend like this:
let a = { "one" : 1, "two" : 2 },
b = { "three" : 3 },
c = { "four" : 4, "five" : 5 };
let d = $.extend({}, a, b, c)
console.log(d)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Underscore has few methods to do this;
1. _.extend(destination, *sources)
Copy all of the properties in the source objects over to the destination object, and return the destination object.
_.extend(a, _.extend(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }
Or
_.extend(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.extend(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }
2. _.defaults(object, *defaults)
Fill in undefined properties in object with values from the defaults objects, and return the object.
_.defaults(a, _.defaults(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }
Or
_.defaults(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.defaults(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }
Shallow-cloning (excluding prototype) or merging of objects is now possible using a shorter syntax than Object.assign().
Spread syntax for object literals was introduced in ECMAScript 2018):
const a = { "one": 1, "two": 2 };
const b = { "three": 3 };
const c = { "four": 4, "five": 5 };
const result = {...a, ...b, ...c};
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }
Spread (...) operator is supported in many modern browsers but not all of them.
So, it is recommend to use a transpiler like Babel to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments.
This is the equivalent code Babel will generate for you:
"use strict";
var _extends = Object.assign || function(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
var a = { "one": 1, "two": 2 };
var b = { "three": 3 };
var c = { "four": 4, "five": 5 };
var result = _extends({}, a, b, c);
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }
Why should the function be restricted to 3 arguments? Also, check for hasOwnProperty.
function Collect() {
var o={};
for(var i=0;i<arguments.length;i++) {
var arg=arguments[i];
if(typeof arg != "object") continue;
for(var p in arg) {
if(arg.hasOwnProperty(p)) o[p] = arg[p];
}
}
return o;
}
It's easy using ES7 spread operator for an object, in your browser console put
({ name: "Alex", ...(true ? { age: 19 } : { })}) // {name: "Alex", age: 19}
({ name: "Alex", ...(false ? { age: 19 } : { })}) // {name: "Alex", }
To merge a dynamic number of objects, we can use Object.assign with spread syntax.
const mergeObjs = (...objs) => Object.assign({}, ...objs);
The above function accepts any number of objects, merging all of their properties into a new object with properties from later objects overwriting those from previous objects.
Demo:
const mergeObjs = (...objs) => Object.assign({}, ...objs);
const a = {prop: 1, prop2: '2'},
b = {prop3: 3, prop4: [1,2,3,4]}
c = {prop5: 5},
d = {prop6: true, prop7: -1},
e = {prop1: 2};
const abcd = mergeObjs(a,b,c,d);
console.log("Merged a,b,c,d:", abcd);
const abd = mergeObjs(a,b,d);
console.log("Merged a,b,d:", abd);
const ae = mergeObjs(a,e);//prop1 from e will overwrite prop1 from a
console.log("Merged a,e:", ae);
To merge an array of objects, a similar method may be applied.
const mergeArrayOfObjs = arr => Object.assign({}, ...arr);
Demo:
const mergeArrayOfObjs = arr => Object.assign({}, ...arr);
const arr = [
{a: 1, b: 2},
{c:1, d:3},
{abcd: [1,2,3,4], d: 4}
];
const merged = mergeArrayOfObjs(arr);
console.log(merged);
function Collect(a, b, c) {
for (property in b)
a[property] = b[property];
for (property in c)
a[property] = c[property];
return a;
}
Notice: Existing properties in previous objects will be overwritten.
ES6 ++
The question is adding various different objects into one.
let obj = {};
const obj1 = { foo: 'bar' };
const obj2 = { bar: 'foo' };
Object.assign(obj, obj1, obj2);
//output => {foo: 'bar', bar: 'foo'};
lets say you have one object with multiple keys that are objects:
let obj = {
foo: { bar: 'foo' },
bar: { foo: 'bar' }
}
this was the solution I found (still have to foreach :/)
let objAll = {};
Object.values(obj).forEach(o => {
objAll = {...objAll, ...o};
});
By doing this we can dynamically add ALL object keys into one.
// Output => { bar: 'foo', foo: 'bar' }
Probably, the fastest, efficient and more generic way is this (you can merge any number of objects and even copy to the first one ->assign):
function object_merge(){
for (var i=1; i<arguments.length; i++)
for (var a in arguments[i])
arguments[0][a] = arguments[i][a];
return arguments[0];
}
It also allows you to modify the first object as it passed by reference.
If you don't want this but want to have a completely new object containing all properties, then you can pass {} as the first argument.
var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge(object1,object2,object3);
combined_object and object1 both contain the properties of object1,object2,object3.
var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge({},object1,object2,object3);
In this case, the combined_object contains the properties of object1,object2,object3 but object1 is not modified.
Check here: https://jsfiddle.net/ppwovxey/1/
Note: JavaScript objects are passed by reference.
Simplest: spread operators
var obj1 = {a: 1}
var obj2 = {b: 2}
var concat = { ...obj1, ...obj2 } // { a: 1, b: 2 }
function collect(a, b, c){
var d = {};
for(p in a){
d[p] = a[p];
}
for(p in b){
d[p] = b[p];
}
for(p in c){
d[p] = c[p];
}
return d;
}

Categories