Both Object.assign and Object spread only do a shallow merge.
An example of the problem:
// No object nesting
const x = { a: 1 }
const y = { b: 1 }
const z = { ...x, ...y } // { a: 1, b: 1 }
The output is what you'd expect. However if I try this:
// Object nesting
const x = { a: { a: 1 } }
const y = { a: { b: 1 } }
const z = { ...x, ...y } // { a: { b: 1 } }
Instead of
{ a: { a: 1, b: 1 } }
you get
{ a: { b: 1 } }
x is completely overwritten because the spread syntax only goes one level deep. This is the same with Object.assign()
.
Is there a way to do this?
This is simple and works:
Explain:
Object.create()
Creates new Object. If you pass params to function it will creates you object with prototype of other object. So if you have any functions on prototype of object they will be passed to prototype of other object.Object.assign()
Merges two objects and creates fully new object and they have no reference anymore. So this example works good for me.Most examples here seem too complex, I'm using one in TypeScript I created, I think it should cover most cases (I'm handling arrays as regular data, just replacing them).
Same thing in plain JS, just in case:
Here are my test cases to show how you could use it
Please let me know if you think I'm missing some functionality.
Here is an immutable (does not modify the inputs) version of @Salakar's answer. Useful if you're doing functional programming type stuff.
Sometimes you don't need deep merge, even if you think so. For example, if you have a default config with nested objects and you want to extend it deeply with your own config, you can create a class for that. The concept is very simple:
You can convert it to a function (not a constructor).
Here is another ES6 solution, works with objects and arrays.
Object.assign documentation suggests it doesn't do deep clone.