JSintroes2022

structuredClone for deep copies

One call, a real deep copy.

Spreading an object copies only the top layer, so nested values stay shared and mutations leak back. structuredClone walks the whole graph for you β€” nested objects, Maps, Sets, Dates, even cycles β€” in a single built-in call, no JSON round-trip and its silent data loss.

The shallow-copy trap

{ ...obj } and Object.assign({}, obj) are shallow copies. They duplicate the outer object, but every nested object, array, or Map is copied by reference β€” the clone and the original point at the same inner values. Mutate one nested field and the "copy" changes too. For flat data that's fine; the moment your data has a second level, a shallow copy is a bug waiting to surprise you.

What structuredClone does

structuredClone(value) is a global function (Node 17+, all modern browsers) that produces a genuine deep copy by recursively walking the value with the structured clone algorithm β€” the same algorithm that powers postMessage and IndexedDB. Nested objects and arrays are fully duplicated, so the result shares nothing mutable with the source.

Beyond JSON: Maps, Sets, Dates, cycles

The old trick, JSON.parse(JSON.stringify(obj)), only understands JSON. It silently destroys a Map, Set, or RegExp (they become {}), turns a Date into a string, drops undefined, and throws on a cyclic reference. structuredClone handles all of these natively: it preserves Map, Set, Date, ArrayBuffer, typed arrays and more, and it tracks objects it has already seen so a self-referencing graph clones cleanly instead of looping forever.

Its limits

structuredClone copies data, not behaviour. It cannot clone a function, a class method, a DOM node, or a Symbol β€” any of those throws a DataCloneError. Class instances lose their prototype and come back as plain objects, and a property whose value is a function makes the whole clone fail. When you need those, reach for a domain-specific copy instead; for plain serialisable state, structuredClone is the right default.

Try it 5 examples

The shallow-copy pitfall

JSintro
Press Run to execute

The spread leaks: writing shallow.nested.retries = 99 also shows 99 on the original because both share one nested object. After structuredClone, setting deep.nested.retries = 1 leaves the original at 99 β€” the nested level is genuinely its own copy.