How to Merge Objects in JavaScript

Object merging allows developers to combine the properties and values of two or more objects into a single object. This is useful for a variety of tasks, including combining default and user-specified values, merging the results of multiple API calls, and joining the properties of an object with the properties of an array.

How to Merge Objects in JavaScript

In JavaScript, object merging combines the properties and values of two or more objects into a single object. This is often useful when working with data in the form of key-value pairs, as it allows you to combine multiple objects into a single data structure.

Object merging is used in a variety of situations, including:

  • Combining the default values of an object with user-specified values
  • Merging the properties of multiple objects into a single object
  • Combining the results of multiple API calls into a single object
  • Joining the properties of an object with the properties of an array

In this post, we will explore the various use cases for object merging in JavaScript and provide examples of how to perform object merging using the (...) spread operator, the built-in Object.assign() method, as well as the merge() function from the popular Lodash library.

The (...) spread operator

The spread operator (...) is considered the most efficient and clean way to combine objects, compared to other alternatives, such as using Object.assign() or manually copying properties from one object to another.

To use the spread operator for object merging, you can use the following syntax:

const defaultOptions = {
  option1: 'value1',
  option2: 'value2'
};

const userOptions = {
  option1: 'overriddenValue1',
  option3: 'newValue3'
};

const mergedOptions = {
  ...defaultOptions,
  ...userOptions
};

console.log(mergedOptions);

/* 
{
    "option1": "overriddenValue1",
    "option2": "value2",
    "option3": "newValue3"
}
*/

In this example, mergedOptions would be a new object that contains all the properties from both defaultOptions and userOptions, with the properties from userOptions taking precedence in case of a conflict.

For comparison, here is a version of the code that uses Object.assign() to achieve the same result:

const defaultOptions = {
  option1: 'value1',
  option2: 'value2'
};

const userOptions = {
  option1: 'overriddenValue1',
  option3: 'newValue3'
};

const mergedOptions = Object.assign({}, defaultOptions, userOptions);

console.log(mergedOptions);

In this example, the console.log statement would output the same object as before:

{
  option1: 'overriddenValue1',
  option2: 'value2',
  option3: 'newValue3'
}

What about deep merges?

If you need to perform a deep merge, where you recursively merge object properties and arrays, the spread operator and Object.assign() are not suitable. These methods only perform a shallow merge, meaning that they only merge the top-level properties of the objects.

One possible way to perform a deep merge is to write a custom function that recursively merges the properties of the objects. This function can use a combination of the spread operator, Object.assign(), and other methods to merge the objects at different levels of depth.

Here is an example of a custom function that performs a deep merge of two objects:

function deepMerge(obj1, obj2) {
  // Create a new object that combines the properties of both input objects
  const merged = {
    ...obj1,
    ...obj2
  };

  // Loop through the properties of the merged object
  for (const key of Object.keys(merged)) {
    // Check if the property is an object
    if (typeof merged[key] === 'object' && merged[key] !== null) {
      // If the property is an object, recursively merge the objects
      merged[key] = deepMerge(obj1[key], obj2[key]);
    }
  }

  return merged;
}

To use this function, you can call it with the two objects you want to merge as arguments:

const defaultOptions = {
  option1: 'value1',
  option2: 'value2',
  nested: {
    subOption1: 'subValue1',
    subOption2: 'subValue2'
  }
};

const userOptions = {
  option1: 'overriddenValue1',
  option3: 'newValue3',
  nested: {
    subOption1: 'overriddenSubValue1',
    subOption3: 'newSubValue3'
  }
};

const mergedOptions = deepMerge(defaultOptions, userOptions);
console.log(mergedOptions);

In this example, the console.log statement would output the following object:

{
  nested: {
    subOption1: "overriddenSubValue1",
    subOption2: "subValue2",
    subOption3: "newSubValue3"
  },
  option1: "overriddenValue1",
  option2: "value2",
  option3: "newValue3"
}

Using Lodash

Lodash is a JavaScript library that provides utility functions for common programming tasks, including the ability to perform a deep merge of objects. To perform a deep merge with Lodash, you can use the merge() function.

The library is available as a browser script or through npm. It goes without saying that using this library is the best approach if you plan on doing production-ready merges!

Here is an example of the merge() function in Lodash:

const _ = require('lodash');

// Define two objects to merge
const obj1 = {
  a: 1,
  b: {
    c: 2,
    d: [3, 4, 5]
  }
};

const obj2 = {
  a: 6,
  b: {
    c: 7,
    d: [8, 9]
  },
  e: 10
};

// Perform the deep merge
const merged = _.merge(obj1, obj2);

console.log(merged);
// Output: { a: 6, b: { c: 7, d: [3, 4, 5, 8, 9] }, e: 10 }

The merge() function will recursively merge the properties of the two objects, including arrays, so that the resulting object contains the properties and values from both objects.

In the case of properties with the same key, the value from the second object (obj2 in this case) will take precedence.