Deep copying is a regular programming task for passing or storing data.
- Shallow copy: Only copies the first level of the object
- Deep copy: Copies all levels of the object
const obj = { name: 'Tari', friends: [{ name: 'Messi'}]};
const shallowCopy = { ...obj };
const deepCopy = dCopy(obj);
console.log(obj.friends === shallowCopy.friends); // ❌ true
console.log(obj.friends === deepCopy.friends); // ✅ false
But all this while we’ve never had a built-in way to perfectly deep copy objects and it’s been a pain.
We always had to lean on third-party libraries for deep copying and keeping circular references.
All that changes now with the new structuredClone()
— an easy and efficient way to deep copy any object.
const obj = { name: 'Tari', friends: [{ name: 'Messi' }] };
const clonedObj = structuredClone(obj);
console.log(obj.name === clonedObj); // false
console.log(obj.friends === clonedObj.friends); // false
Cloning circular references with ease:
const car = {
make: 'Toyota',
};
// 👉 Circular reference
car.basedOn = car;
const cloned = structuredClone(car);
console.log(car.basedOn === cloned.basedOn); // false
// 👇 Circular reference is cloned
console.log(car === car.basedOn); // true
Something you could never do with the JSON
stringify
/parse
hack:
Go as deep as you want:
// ↘️
const obj = {
a: {
b: {
c: {
d: {
e: 'Coding Beauty',
},
},
},
},
};
const clone = structuredClone(obj);
console.log(clone.a.b.c.d === obj.a.b.c.d); // ✅ false
console.log(clone.a.b.c.d.e); // Coding Beauty
Limitations you should know
structuredClone()
is very powerful but it has important weaknesses you should know:
Can’t clone functions or methods
Because of the special algorithm it uses.
Can’t clone DOM elements
Doesn’t preserve RegExp
lastIndex
property
I mean, no one’s cloning regexes but it’s one to note:
const regex = /beauty/g;
const str = 'Coding Beauty: JS problems are solved at Coding Beauty';
console.log(regex.index);
console.log(regex.lastIndex); // 7
const regexClone = structuredClone(regex);
console.log(regexClone.lastIndex); // 0
Other limitations
Important to be aware of them to avoid unexpected behavior when using the function.
Clone some, move
This is a more sophisticated one.
You transfer inner objects from source to clone instead of copying.
Which means there’s nothing left in source to change:
const uInt8Array = Uint8Array.from({ length: 1024 * 1024 * 16 }, (v, i) => i);
const transferred = structuredClone(uInt8Array, {
transfer: [uInt8Array.buffer],
});
console.log(uInt8Array.byteLength); // 0
Overall structuredClone()
is a valuable addition to a developer’s toolkit and makes object cloning easier than ever in JavaScript
Every Crazy Thing JavaScript Does
A captivating guide to the subtle caveats and lesser-known parts of JavaScript.