AskHandle Blog
How can I deeply merge two objects in JavaScript?

How can I deeply merge two objects in JavaScript?
When working with JavaScript, especially in projects involving configurations or complex data structures, you often need to combine two objects into one. Sometimes, a simple merge that overwires properties at the top level isn’t enough. Instead, you need to merge objects deeply, combining nested objects as well. This is a common question during technical interviews because deep merging involves understanding recursion, object handling, and sometimes third-party libraries.
A shallow merge using Object.assign() or the spread operator ({...obj1, ...obj2}) copies only the first level of an object. For example:
1const obj1 = { a: 1, b: { c: 2 } };
2const obj2 = { b: { d: 3 } };
3
4const merged = { ...obj1, ...obj2 }; // { a: 1, b: { d: 3 } }In this case, the b property from obj2 overwrites the b property in obj1. Notice how the nested object b is replaced entirely, not merged.
To perform a deep merge, you need to recursively traverse both objects and merge their properties. Here’s a simple implementation of a deep merge function:
1function deepMerge(target, source) {
2 // Loop through each property in the source object
3 for (const key in source) {
4 // Check if the property exists in source
5 if (source.hasOwnProperty(key)) {
6 const sourceValue = source[key];
7 const targetValue = target[key];
8
9 // If both values are objects, recurse
10 if (
11 sourceValue && typeof sourceValue === 'object' &&
12 targetValue && typeof targetValue === 'object'
13 ) {
14 deepMerge(targetValue, sourceValue);
15 } else {
16 // Otherwise, assign the source value to target
17 target[key] = sourceValue;
18 }
19 }
20 }
21 return target;
22}You can use this function like this:
1const obj1 = { a: 1, b: { c: 2 } };
2const obj2 = { b: { d: 3 }, e: 4 };
3
4const mergedObject = deepMerge({ ...obj1 }, obj2);
5console.log(mergedObject);
6// Output: { a: 1, b: { c: 2, d: 3 }, e: 4 }It’s important to note that this implementation modifies the first object you pass to it, so if you want to keep your original objects unchanged, you should pass a copy of the first object, like in the example above ({ ...obj1 }).
There are also popular utility libraries like Lodash that offer a _.merge() method, which performs deep merging easily:
1const _ = require('lodash');
2
3const obj1 = { a: 1, b: { c: 2 } };
4const obj2 = { b: { d: 3 }, e: 4 };
5
6const mergedObject = _.merge({}, obj1, obj2);
7console.log(mergedObject);
8// Output: { a: 1, b: { c: 2, d: 3 }, e: 4 }Using such libraries can simplify your code and improve reliability, especially for more complex cases.