Deep-merge two plain objects
Implement deepMerge(a, b) that returns a NEW object combining a and b. When both have the same key and both values are plain objects, merge them recursively; otherwise b's value wins. Neither input may be mutated. deepMerge({x: {p: 1}}, {x: {q: 2}}) returns {x: {p: 1, q: 2}}.
function deepMerge(a, b) {
// your code here
}
Write the implementation.
Start with a shallow copy { ...a }. For each key of b, if both a[key] and b[key] are plain objects, set the result key to deepMerge(a[key], b[key]) recursively; otherwise assign b[key]. The recursion merges nested objects, and copying first means neither input is mutated. Non-object values from b overwrite.
- ✗Using
Object.assignor spread, which only merges the top level (shallow) - ✗Mutating
ain place instead of building and returning a new object - ✗Treating arrays or
nullas plain objects to recurse into
- →How would you decide whether a value is a 'plain object' versus an array or
null? - →How should the merge behave when one key holds an array on each side?
Solution
Copy a, then for each key of b recursively merge nested objects or overwrite.
function deepMerge(a, b) {
const isPlain = (v) =>
v !== null && typeof v === 'object' && !Array.isArray(v);
const result = { ...a };
for (const key of Object.keys(b)) {
if (isPlain(result[key]) && isPlain(b[key])) {
result[key] = deepMerge(result[key], b[key]);
} else {
result[key] = b[key];
}
}
return result;
}
How it works
{ ...a } creates a new object with a copy of a's top-level keys, so the original objects are never mutated. We then iterate b's keys: when both the current value and b's value are plain objects (isPlain excludes arrays and null), we merge them with a recursive deepMerge call. Otherwise b's value wins and overwrites.
The recursion reaches any nesting depth, so shared sub-objects are combined rather than wholesale replaced. Arrays and primitives are treated as leaves and simply assigned. </content>