In vanilla JavaScript, there are multiple ways available to combine properties of two objects to create a new object. You can use ES6 methods like Object.assign() and spread operator (...) to perform a shallow merge of two objects. For a deeper merge, you can either write a custom function or use Lodash's merge() method.

In this article, you'll learn about all these methods with examples. Let us start with the Object.assign() method.

Object.assign() Method

The Object.assign(target, source1, soure2, ...) method is part of ES6 (ESMAScript 2015) and copies all enumerable own properties of one or more source objects to a target object, and returns the target object.

Here is an example:

const profile = {
    name: 'John Doe',
    age: 25
};

const job = {
    profession: 'IT Engineer'
};

const user = Object.assign(profile, job);

console.log(user);
// { name: 'John Doe', age: 25, profession: 'IT Engineer' }

There's no limit to the number of objects you can merge with Object.assign(). All objects get merged into the first object. Only the target object is mutated and returned. All other objects remain the same. If you don't want to mutate the target object too, simply pass an empty object {} as target:

const obj1 = { a: 1 };
const obj2 = { b: 2 };
const obj3 = { c: 3 };

const obj = Object.assign({}, obj1, obj2, obj3);

console.log(obj);
// { a: 1, b: 2, c: 3 }

The properties are overwritten by other objects that have the same properties later in the parameters order:

const obj1 = { a: 1, b: 1, c: 1 };
const obj2 = { b: 2, c: 2 };
const obj3 = { c: 3 };

const obj = Object.assign({}, obj1, obj2, obj3);

console.log(obj); 
// { a: 1, b: 2, c: 3 }

Spread Operator

The second way to merge objects in JavaScript is by using the spread syntax (...). Spread operators were originally introduced in ES6 (ECMAScript 2015) but object literals spread support was added in ES9 (ECMAScript 2018).

Here is an example:

const profile = {
    name: 'John Doe',
    age: 25
};

const job = {
    profession: 'IT Engineer'
};

const user = { ...profile, ...job };

console.log(user);
// { name: 'John Doe', age: 25, profession: 'IT Engineer' }

The object spread is a fairly new feature and only works in the latest versions of modern browsers. Just like Object.assign(), it allows you to merge any number of objects with similar handling of duplicate keys.

Custom Function

You can also write your own custom function to merge two or more objects:

const merge = (...arguments) => {

    // create a new object
    let target = {};

    // merge the object into the target object
    const merger = (obj) => {
        for (let prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                target[prop] = obj[prop];
            }
        }
    };

    // iterate through all objects and merge them with target
    for (let i = 0; i < arguments.length; i++) {
        merger(arguments[i]);
    }

    return target;
};


const profile = {
    name: 'John Doe',
    age: 25
};

const job = {
    profession: 'IT Engineer'
};

const user = merge(profile, job);

console.log(user);
// { name: 'John Doe', age: 25, profession: 'IT Engineer' }

Deep Merge Objects

To deep merge two or more objects, you have to recursively copy all objects' own properties, nested arrays, functions, and extended properties to the target object.

Let us extend the above function to perform a deep merger of multiple objects:

const merge = (...arguments) => {

    // create a new object
    let target = {};

    // deep merge the object into the target object
    const merger = (obj) => {
        for (let prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                if (Object.prototype.toString.call(obj[prop]) === '[object Object]') {
                    // if the property is a nested object
                    target[prop] = merge(target[prop], obj[prop]);
                } else {
                    // for regular property
                    target[prop] = obj[prop];
                }
            }
        }
    };

    // iterate through all objects and 
    // deep merge them with target
    for (let i = 0; i < arguments.length; i++) {
        merger(arguments[i]);
    }

    return target;
};


const profile = {
    name: 'John Doe',
    age: 25,
    address: {
        city: 'Berlin',
        country: 'DE'
    }
};

const job = {
    profession: 'IT Engineer',
    skills: ['JavaScript', 'React', 'Node']
};

// perform deep merge
const user = merge(profile, job);

console.log(user);

// {
//     name: 'John Doe',
//     age: 25,
//     address: { city: 'Berlin', country: 'DE' },
//     profession: 'IT Engineer',
//     skills: ['JavaScript', 'React', 'Node']
// }

Lodash's merge() Method

You can also use Lodash's merge() method to perform a deep merger of objects. This method recursively merges two or more source objects properties into a target object.

Here is an example:

const _ = require('lodash');

const profile = {
    name: 'John Doe',
    age: 25,
    address: {
        city: 'Berlin',
        country: 'DE'
    }
};

const job = {
    profession: 'IT Engineer',
    skills: ['JavaScript', 'React', 'Node']
};

// deep merge objects
const user = _.merge(profile, job);

console.log(user);

// {
//     name: 'John Doe',
//     age: 25,
//     address: { city: 'Berlin', country: 'DE' },
//     profession: 'IT Engineer',
//     skills: ['JavaScript', 'React', 'Node']
// }

To learn more about JavaScript objects, prototypes, and classes, take a look at this guide.

✌️ Like this article? Follow @attacomsian on Twitter. You can also follow me on LinkedIn and DEV. Subscribe to RSS Feed.

👋 If you enjoy reading my articles and want to support me to continue creating free tutorials, ☕ Buy me a coffee (cost $5).