JavaScript can do a lot! It's the language of the internet and also pays my bills. Still, there are some surprising frustrations about JavaScript. Some of them seem unbelievable. One of these is deep-copying
Objects. 🤦♂️
JavaScript does not support deep-copying
Objects. ES6 introduced some useful ways to do shallow-copying
, like Object.assign
and the spread operator
, but it's important to remember these DO NOT deep-copy
. Nested objects remain a reference to the original object.
const obj = {a: 0} // obj.a = 0} 🙂
const clone = obj // obj.a = 0} 🙂 clone.a = 0} 🙂
obj.a++ // obj.a = 1} 🤬 clone.a = 1} 🤬
clone.a = 5 // obj.a = 5} 🤬 clone.a = 5} 🤬
The complete technical explanation can get complex, but the tl;dr
is that clone
is linked to obj
. It's not a proper clone. It's a reference to the original. Changing properties for one of them will change the same property for the other. 🤦♂️
Kind of. The Object.assign
method and spread operator
only do shallow-copying
. I'll just show the spread operator
because as far as I know, they work the same in this case.
const obj = {a: 0} // obj.a = 0 🙂
const clone = {...obj} // obj.a = 0 🙂 clone.a = 0 🙂
obj.a++ // obj.a = 1 🙂 clone.a = 0 🙂
clone.a = 5 // obj.a = 1 🙂 clone.a = 5 🙂
Great, right?
Unfortunately they don't work on nested
objects. 🤦♂️
const obj = {a: 0, b:{c: 0}} // obj.b.c = 0 🙂
const clone = {...obj} // obj.b.c = 0 🙂 clone.b.c = 0 🙂
obj.b.c++ // obj.b.c = 1 🤬 clone.b.c = 1 🤬
clone.b.c = 5 // obj.b.c = 5 🤬 clone.b.c = 5 🤬
The nested
objects remain linked to the original object just like the first example. It's important to be aware of this when using the ES6 features mentioned.
Apparently const clone = JSON.parse(JSON.stringify(obj))
works except for:
Dates
- Functions
undefined
- regExp
Infinity
It's a shame that JavaScript needs to rely on libraries, custom algorithms, or sketchy JSON
workarounds. 😞
At least the ES6 goodies did improve the status quo a bit.
- Long StackOverflow page with an alarming number of answers suggesting the
JSON.stringify
method.