Master Deep Cloning in JavaScript with structuredClone()
This article explores the modern JavaScript global function structuredClone() as a robust solution for deep cloning objects, comparing it with traditional spread, JSON methods, and custom recursion, and covering handling of circular references, functions, undefined values, performance benchmarks, supported types, and limitations.
Classic interview question: how to implement deep copy.
Common answers use JSON or recursive traversal, testing familiarity with object manipulation. This article introduces another solution: structuredClone(). structuredClone() is a global function introduced in 2022 that enables true deep cloning of JavaScript objects, handling complex structures and circular references that break JSON.stringify() / JSON.parse().
Basic Usage
It creates a genuine deep clone, preserving nested objects and circular references without extra logic, and works in modern environments including Web Workers.
1. Simple Object Clone
Using the spread operator {...obj} creates a shallow copy:
const original = {name: "Alice", details: {age: 25}};
const shallowCopy = { ...original };
shallowCopy.details.age = 30;
console.log(original.details.age); // 30
console.log(shallowCopy.details.age); // 30The change to shallowCopy.details also affects original.details because only a shallow copy was made.
Deep copy with JSON:
const original = {name: "Alice", details: {age: 25}};
const deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.details.age = 30;
console.log(original.details.age); // 25
console.log(deepCopy.details.age); // 30This method cannot clone functions, undefined, or circular references.
Deep copy with structuredClone():
const original = {name: "Alice", details: {age: 25}};
const clone = structuredClone(original);
clone.details.age = 30;
console.log(original.details.age); // 25
console.log(clone.details.age); // 30 structuredClone()produces a deep clone without the limitations of JSON.stringify().
2. Circular References
The spread operator fails with circular references, causing errors.
JSON also throws a TypeError when encountering circular structures. structuredClone() handles circular references gracefully:
const original = {name: "Alice", self: null};
original.self = original;
const clone = structuredClone(original);
console.log(clone !== original); // true
console.log(clone.self === clone); // true3. Functions and undefined
Spread copies functions and undefined shallowly, but they are not deep‑cloned.
JSON loses both functions and undefined values. structuredClone() does not clone functions (they become undefined) but preserves undefined values, making it more reliable than JSON for complex objects.
4. Performance
Benchmark with a large array shows structuredClone() is typically faster than the JSON stringify/parse combination and avoids serialization overhead.
const largeArray = new Array(1e6).fill({key: "value"});
console.time("structuredClone");
const clone = structuredClone(largeArray);
console.timeEnd("structuredClone");
console.time("JSON.stringify + JSON.parse");
const jsonCopy = JSON.parse(JSON.stringify(largeArray));
console.timeEnd("JSON.stringify + JSON.parse");Deep Dive
The global structuredClone() uses the structured cloning algorithm, which can also transfer transferable objects instead of copying them.
Signature: structuredClone(value, { transfer }) value : any value supported by the algorithm.
Supported types include Array, ArrayBuffer, Boolean, DataView, Date, certain Error types, Map, plain objects, primitive types (except Symbol), RegExp (without lastIndex), Set, String, TypedArray, etc.
transfer (optional) : an array of transferable objects whose ownership is moved to the clone, leaving the original empty.
Example of transferring a large Uint8Array:
var uInt8Array = new Uint8Array(1024 * 1024 * 16); // 16 MB
for (var i = 0; i < uInt8Array.length; ++i) { uInt8Array[i] = i; }
const transferred = structuredClone(uInt8Array, { transfer: [uInt8Array.buffer] });
console.log(uInt8Array.byteLength); // 0The algorithm cannot clone Function objects, DOM nodes, or preserve certain object metadata such as property descriptors, getters/setters, prototype chain, and RegExp lastIndex.
Conclusion
Reliability: Predictably handles circular references, functions, and undefined values.
Efficiency: Faster deep cloning for large data sets without work‑arounds.
Simplicity: One method replaces spread, JSON tricks, and custom deep‑clone functions.
Code Mala Tang
Read source code together, write articles together, and enjoy spicy hot pot together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
