How can I merge properties of two JavaScript objects dynamically?

Viewed 1766783

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.

69 Answers

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-transform-object-rest-spread plugin for it to work.

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.

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

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

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!

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

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

let obj1 = {a:1, b:2};
let obj2 = {c:3, d:4};
let merged = {...obj1, ...obj2};
console.log(merged);

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);

ES2018/TypeScript: Many answers are OK but I've come up with a more elegant solution to this problem when you need to merge two objects without overwriting overlapping object keys.

My function also accepts unlimited number of objects to merge as function arguments:

(I'm using TypeScript notation here, feel free to delete the :object[] type in the function argument if you're using plain JavaScript).

const merge = (...objects: object[]) => {
  return objects.reduce((prev, next) => {
    Object.keys(prev).forEach(key => {
      next[key] = { ...next[key], ...prev[key] }
    })
    return next
  })
}

You can use Object.assign method. For example:

var result = Object.assign(obj1, obj2);

Also, note that it creates a shallow copy of the object.

Use Spread operator which follows the ES6 version

var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
let result = {...obj1,...obj2};
console.log(result)

output { food: 'pizza', car: 'ford', animal: 'dog' }
Object.assign(TargetObject, Obj1, Obj2, ...);

shallow

var obj = { name : "Jacob" , address : ["America"] }
var obj2 = { name : "Shaun" , address : ["Honk Kong"] }

var merged = Object.assign({} , obj,obj2 ); //shallow merge 
obj2.address[0] = "new city"

result.address[0] is changed to "new city" , i.e merged object is also changed. This is the problem with shallow merge.

deep

var obj = { name : "Jacob" , address : ["America"] }
var obj2 = { name : "Shaun" , address : ["Honk Kong"] }

var result = Object.assign({} , JSON.parse(JSON.stringify(obj)),JSON.parse(JSON.stringify(obj2)) )

obj2.address[0] = "new city"

result.address[0] is not changed

The correct implementation in Prototype should look like this:

var obj1 = {food: 'pizza', car: 'ford'}
var obj2 = {animal: 'dog'}

obj1 = Object.extend(obj1, obj2);

I've used Object.create() to keep the default settings (utilising __proto__ or Object.getPrototypeOf() ).

function myPlugin( settings ){
    var defaults = {
        "keyName": [ "string 1", "string 2" ]
    }
    var options = Object.create( defaults );
    for (var key in settings) { options[key] = settings[key]; }
}
myPlugin( { "keyName": ["string 3", "string 4" ] } );

This way I can always 'concat()' or 'push()' later.

var newArray = options['keyName'].concat( options.__proto__['keyName'] );

Note: You'll need to do a hasOwnProperty check before concatenation to avoid duplication.

With the following helper, you can merge two objects into one new object:

function extend(obj, src) {
    for (var key in src) {
        if (src.hasOwnProperty(key)) obj[key] = src[key];
    }
    return obj;
}

// example
var a = { foo: true }, b = { bar: false };
var c = extend(a, b);

console.log(c);
// { foo: true, bar: false }

This is typically useful when merging an options dict with the default settings in a function or a plugin.

If support for IE 8 is not required, you may use Object.keys for the same functionality instead:

function extend(obj, src) {
    Object.keys(src).forEach(function(key) { obj[key] = src[key]; });
    return obj;
}

This involves slightly less code and is a bit faster.

merge two object using Object.assign and spread operator.

Wrong way(Modify original object because targeting o1)

var o1 = { X: 10 };
var o2 = { Y: 20 };
var o3 = { Z: 30 };
var merge = Object.assign(o1, o2, o3);
console.log(merge)  // {X:10, Y:20, Z:30}
console.log(o1)     // {X:10, Y:20, Z:30}

Right ways

  • Object.assign({}, o1, o2, o3) ==> targeting new object

  • {...o1, ...o2, ...o3} ==> spreading objects

var o1 = { X: 10 };
var o2 = { Y: 20 };
var o3 = { Z: 30 };

console.log('Does not modify original objects because target {}');
var merge = Object.assign({}, o1, o2, o3);
console.log(merge); // { X: 10, Y: 20, Z: 30 }
console.log(o1)

console.log('Does not modify original objects')
var spreadMerge = {...o1, ...o2, ...o3};
console.log(spreadMerge);
console.log(o1);

There are different ways to achieve this:

Object.assign(targetObj, sourceObj);

targetObj = {...targetObj, ...sourceObj};

Use this

var t=merge({test:123},{mysecondTest:{blub:{test2:'string'},args:{'test':2}}})
console.log(t);

function merge(...args) {
  return Object.assign({}, ...args);
}

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject={
  ...firstObject,
  key3 : 'value3',
  key4 : 'value4',
  key5 : 'value5'
}
console.log(firstObject);
console.log(secondObject);

We can crate a empty object, and combine them by for-loop:

var obj1 = {
  id: '1',
  name: 'name'
}

var obj2 = {
  c: 'c',
  d: 'd'
}

var obj3 = {}

for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }


console.log( obj1, obj2, obj3)

Three ways you can do that:-

Approach 1:-

// using spread ...
    let obj1 = {
        ...obj2
    };

Approach2:-

// using  Object.assign() method
let obj1 = Object.assign({}, obj2);

Approach3:-

// using JSON
let obj1 = JSON.parse(JSON.stringify(obj2));

Try this way using jQuery library

let obj1 = { food: 'pizza', car: 'ford' }
let obj2 = { animal: 'dog' }

console.log(jQuery.extend(obj1, obj2))
Related