This ought to do what you're looking for. It will recursively merge arbitrarily deep objects into arrays.
// deepmerge by Zachary Murray (dremelofdeath) CC-BY-SA 3.0
function deepmerge(foo, bar) {
var merged = {};
for (var each in bar) {
if (foo.hasOwnProperty(each) && bar.hasOwnProperty(each)) {
if (typeof(foo[each]) == "object" && typeof(bar[each]) == "object") {
merged[each] = deepmerge(foo[each], bar[each]);
} else {
merged[each] = [foo[each], bar[each]];
}
} else if(bar.hasOwnProperty(each)) {
merged[each] = bar[each];
}
}
for (var each in foo) {
if (!(each in bar) && foo.hasOwnProperty(each)) {
merged[each] = foo[each];
}
}
return merged;
}
And this one will do the same, except that the merged object will include copies of inherited properties. This probably isn't what you're looking for (as per RobG's comments below), but if that is actually what you are looking for, then here it is:
// deepmerge_inh by Zachary Murray (dremelofdeath) CC-BY-SA 3.0
function deepmerge_inh(foo, bar) {
var merged = {};
for (var each in bar) {
if (each in foo) {
if (typeof(foo[each]) == "object" && typeof(bar[each]) == "object") {
merged[each] = deepmerge(foo[each], bar[each]);
} else {
merged[each] = [foo[each], bar[each]];
}
} else {
merged[each] = bar[each];
}
}
for (var each in foo) {
if (!(each in bar)) {
merged[each] = foo[each];
}
}
return merged;
}
I tried it out with your example on http://jsconsole.com, and it worked fine:
deepmerge(foo, bar)
{"a": [1, 3], "b": [2, 4]}
bar
{"a": 3, "b": 4}
foo
{"a": 1, "b": 2}
Slightly more complicated objects worked as well:
deepmerge(as, po)
{"a": ["asdf", "poui"], "b": 4, "c": {"q": [1, 444], "w": [function () {return 5;}, function () {return 1123;}]}, "o": {"b": {"t": "cats"}, "q": 7}, "p": 764}
po
{"a": "poui", "c": {"q": 444, "w": function () {return 1123;}}, "o": {"b": {"t": "cats"}, "q": 7}, "p": 764}
as
{"a": "asdf", "b": 4, "c": {"q": 1, "w": function () {return 5;}}}
Answer from Zachary Murray on Stack Overflowjavascript - Merge JS objects without overwriting - Stack Overflow
How can I merge properties of two JavaScript objects? - Stack Overflow
How do you merge two objects with the same properties without overriding them?
Merge two javascript objects without overwriting - Stack Overflow
This ought to do what you're looking for. It will recursively merge arbitrarily deep objects into arrays.
// deepmerge by Zachary Murray (dremelofdeath) CC-BY-SA 3.0
function deepmerge(foo, bar) {
var merged = {};
for (var each in bar) {
if (foo.hasOwnProperty(each) && bar.hasOwnProperty(each)) {
if (typeof(foo[each]) == "object" && typeof(bar[each]) == "object") {
merged[each] = deepmerge(foo[each], bar[each]);
} else {
merged[each] = [foo[each], bar[each]];
}
} else if(bar.hasOwnProperty(each)) {
merged[each] = bar[each];
}
}
for (var each in foo) {
if (!(each in bar) && foo.hasOwnProperty(each)) {
merged[each] = foo[each];
}
}
return merged;
}
And this one will do the same, except that the merged object will include copies of inherited properties. This probably isn't what you're looking for (as per RobG's comments below), but if that is actually what you are looking for, then here it is:
// deepmerge_inh by Zachary Murray (dremelofdeath) CC-BY-SA 3.0
function deepmerge_inh(foo, bar) {
var merged = {};
for (var each in bar) {
if (each in foo) {
if (typeof(foo[each]) == "object" && typeof(bar[each]) == "object") {
merged[each] = deepmerge(foo[each], bar[each]);
} else {
merged[each] = [foo[each], bar[each]];
}
} else {
merged[each] = bar[each];
}
}
for (var each in foo) {
if (!(each in bar)) {
merged[each] = foo[each];
}
}
return merged;
}
I tried it out with your example on http://jsconsole.com, and it worked fine:
deepmerge(foo, bar)
{"a": [1, 3], "b": [2, 4]}
bar
{"a": 3, "b": 4}
foo
{"a": 1, "b": 2}
Slightly more complicated objects worked as well:
deepmerge(as, po)
{"a": ["asdf", "poui"], "b": 4, "c": {"q": [1, 444], "w": [function () {return 5;}, function () {return 1123;}]}, "o": {"b": {"t": "cats"}, "q": 7}, "p": 764}
po
{"a": "poui", "c": {"q": 444, "w": function () {return 1123;}}, "o": {"b": {"t": "cats"}, "q": 7}, "p": 764}
as
{"a": "asdf", "b": 4, "c": {"q": 1, "w": function () {return 5;}}}
Presumably you would iterate over one object and copy its property names to a new object and values to arrays assigned to those properties. Iterate over subsequent objects, adding properties and arrays if they don't already exist or adding their values to existing properties and arrays.
e.g.
function mergeObjects(a, b, c) {
c = c || {};
var p;
for (p in a) {
if (a.hasOwnProperty(p)) {
if (c.hasOwnProperty(p)) {
c[p].push(a[p]);
} else {
c[p] = [a[p]];
}
}
}
for (p in b) {
if (b.hasOwnProperty(p)) {
if (c.hasOwnProperty(p)) {
c[p].push(b[p]);
} else {
c[p] = [b[p]];
}
}
}
return c;
}
You could modify it to handle any number of objects by iterating over the arguments supplied, but that would make passing the object to merge into more difficult.
With Underscore.js, to merge an array of objects do:
var arrayOfObjects = [ {a:1}, {b:2, c:3}, {d:4} ];
_(arrayOfObjects).reduce(function(memo, o) { return _(memo).extend(o); });
It results in:
Object {a: 1, b: 2, c: 3, d: 4}
You should use lodash's defaultsDeep
_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// โ { 'user': { 'name': 'barney', 'age': 36 } }
Hi, I would greatly appreciate your help if anyone of you have the time to help me solve this problem.
I'm trying to merge these two objects:
const userx = {
name: 'Alex',
address: '15th Park Avenue',
age: 43,
};
const department = {
id: '001',
Shift: 'Morning',
name: 'Sales',
};
// solutions tried:
1st -
const completeDetails = { ...userx, ...department }; // Shift: "Morning", address: "15th Park Avenue", age: 43id: "001", name: "Sales"
2nd -
const completeDetails = JSON.parse(JSON.stringify({ ...userx, ...department })); Shift: "Morning", address: "15th Park Avenue", age: 43id: "001", name: "Sales"
I tried deep cloning but as you can see it still overrides the name property. I would like the output to be:
name: 'Alex',
address: "15th Park Avenue",
age: 43,
id: "001",
Shift: "Morning",
name: "Sales"
For those who don't use jQuery, here comes a vanilla-js solution.
Solution:
function extend (target) {
for(var i=1; i<arguments.length; ++i) {
var from = arguments[i];
if(typeof from !== 'object') continue;
for(var j in from) {
if(from.hasOwnProperty(j)) {
target[j] = typeof from[j]==='object'
? extend({}, target[j], from[j])
: from[j];
}
}
}
return target;
}
Compressed (with Closure Compiler):
Only 199 characters!
var extend=function e(c){for(var d=1;d<arguments.length;++d){var a=arguments[d];if("object"===typeof a)for(var b in a)a.hasOwnProperty(b)&&(c[b]="object"===typeof a[b]?e({},c[b],a[b]):a[b])}return c}
How to use:
extend(target, obj1, obj2); // returns target
If you only want to merge, use
var merged = extend({}, obj1, obj2);
Features:
- It doesn't look at objects' prototype.
- Ignores non-objects.
- It is recursive in order to merge properties which are objects.
- Objects referenced in
target's properties, if extended, are replaced by new ones, and the original ones are not modified. - In case of same property names, the merged value will be the merging of the objects after the last (in the order of arguments) non-object value. Or, if the last isn't an object, itself.
Examples:
extend({}, {a:1}, {a:2}); // {a:2}
extend({}, {a:1}, {b:2}); // {a:1, b:2}
extend({}, {a: {b:1}}, {a: {b:2}}); // {a: {b:2}}
extend({}, {a: {b:1}}, {a: {c:2}}); // {a: {b:2, c:2}}
extend({}, {a: {a:1}}, {a: {b:2}}, {a: 'whatever non object'});
// {a: "whatever non object"}
extend({}, {a: {a:1}}, {a: {b:2}}, {a: 'whatever non object'}, {a: {c:3}},{a: {d:4}});
// {a: {c:3, d:4}}
Warning:
Be aware that if browser is not clever enough, it could be trapped in an infinite loop:
var obj1={},
obj2={};
obj1.me=obj1;
obj2.me=obj2;
extend({},obj1,obj2);
If the browser is clever enough, it can throw an error, or return {me: undefined}, or whatever.
Note that this warning also applies if you use jQuery's $.extend.
With ES2015 now being supported in all modern browsers, the native Object.assign can be used to extend objects
Object.assign({}, _default, values)
Object.assign
Note that default is a reserved keyword, and can't be used as a variable name
The original answer, written in 2013 :
Since this is tagged with jQuery, you could use $.extend for a simple cross-browser solution
var temp = {};
$.extend(true, temp, _default, values);
values = temp;
const obj1 = { a: 10, b: 13 }
const obj2 = { a: 84, c: 70, d: 40 }
function foo(obj1, obj2) {
const newObject = {}
for (const key in { ...obj1, ...obj2 }) {
const element1 = obj1[key];
const element2 = obj2[key];
if (element1 && element2)
newObject[key] = [element1, element2]
else if (element1)
newObject[key] = element1
else if (element2)
newObject[key] = element2
}
return newObject
}
console.log(foo(obj1, obj2))
Here is two solutions, The first one, merge the values of the keys into an object under the same key name. The second one, propose a way to merge them as you mention, but it is a bit more complicated to maintain the index of each key but it is still possible.
The result of both options looks like that
// Option 1
{ a: [ 10, 11, 84 ], b: [ 13, 12 ], c: 70, d: 50 }
// Option 2
{
a: { '0': 10, '1': 11, '2': 84 },
b: { '0': 13, '1': 12 },
c: 70,
d: 50
}
And here is how it is achieved
const obj1 = { a: { 0: 10, 1: 11 }, b: 13 }
const obj2 = { a: 84, b: 12, c: 70, d: 50 }
const allKeys = Object.keys({ ...obj1, ...obj2 });
const merged1 = {};
for (const key of allKeys) {
const isObj1Object = typeof obj1[key] === 'object';
const isObj2Object = typeof obj2[key] === 'object';
if (obj1[key] && obj2[key]) {
merged1[key] = [
...(isObj1Object ? Object.values(obj1[key]) : [obj1[key]]),
...(isObj2Object ? Object.values(obj2[key]) : [obj2[key]]),
];
} else if (obj1[key] || obj2[key]) {
merged1[key] = obj1[key] || obj2[key];
}
}
console.log(merged1);
const merged2 = {};
for (const key of allKeys) {
if (obj1[key] && obj2[key]) {
const isObj1Object = typeof obj1[key] === 'object';
const isObj2Object = typeof obj2[key] === 'object';
merged2[key] = {
...(
isObj1Object
? Object.values(obj1[key]).reduce((acc, v, i) => {
acc[Object.keys(obj2[key]).length + i] = v;
return acc;
}, {})
: (
isObj2Object
? { [Object.keys(obj2[key]).length]: obj1[key] }
: { 0: obj1[key] }
)
),
...(
isObj2Object
? Object.values(obj2[key]).reduce((acc, v, i) => {
acc[Object.keys(obj1[key]).length + i] = v;
return acc;
}, {})
: (
isObj1Object
? { [Object.keys(obj1[key]).length]: obj2[key] }
: { 1: obj2[key] })
),
};
} else if (obj1[key] || obj2[key]) {
merged2[key] = obj1[key] || obj2[key];
}
}
console.log(merged2);
You can test the different options here playground
If you would like to have a deep merged without any level limitation you would have to update the code to use a recursive method.