Mastering Deep Cloning in JavaScript with structuredClone()

This article explains how the new global function structuredClone() provides a reliable, fast, and simple way to deep‑clone JavaScript objects—including nested structures, circular references, and undefined values—outperforming traditional JSON or manual recursion methods.

Code Mala Tang
Code Mala Tang
Code Mala Tang
Mastering Deep Cloning in JavaScript with structuredClone()

Classic interview question: how to achieve deep copy.

Common answers use JSON.stringify/parse or recursive traversal; this article introduces another solution: structuredClone().

structuredClone()

is a global function introduced in 2022 that enables deep cloning of JavaScript objects, handling complex structures and circular references that JSON methods cannot.

Basic Usage

It creates a true deep clone, preserving nested objects and circular references without extra logic, and works in modern environments including Web Workers.

1. Simple Object Clone: Basics

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); // 30

The spread operator only copies the top level; changes to nested objects affect the original.

Using JSON.stringify() + JSON.parse() creates a deep copy but cannot handle functions, undefined, or circular references.

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); // 30

Using structuredClone() for deep copy:

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()

preserves structure without the limitations of JSON methods and can handle circular references and undefined.

2. Circular References

The spread operator cannot handle circular references and throws an error.

const original = {
  name: "Alice",
  self: null
};

original.self = original; // circular reference

const shallowCopy = { ...original }; // TypeError

JSON methods also fail with circular structures.

const jsonCopy = JSON.parse(JSON.stringify(original)); // TypeError
structuredClone()

easily clones objects with circular references:

const original = {
  name: "Alice",
  self: null
};

original.self = original;

const clone = structuredClone(original);
console.log(clone !== original); // true
console.log(clone.self === clone); // true

3. Functions and undefined

Spread operator copies functions and undefined shallowly.

const original = {
  name: "Alice",
  greet: () => "Hello!",
  value: undefined
};

const shallowCopy = { ...original };
console.log(shallowCopy.greet()); // "Hello!"
console.log(shallowCopy.value); // undefined

JSON.stringify cannot serialize functions or undefined, so they are lost.

const jsonCopy = JSON.parse(JSON.stringify(original));
console.log(jsonCopy.greet); // undefined
console.log(jsonCopy.value); // undefined
structuredClone()

also does not clone functions but retains undefined values, making it more reliable than JSON methods.

4. Speed and Efficiency

For large data sets, structuredClone() is generally faster than the JSON approach.

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 clone algorithm to deep copy any supported value. It also supports transferring transferable objects instead of copying them.

structuredClone(value, { transfer })

value – the object to clone; any type supported by the algorithm.

Supported JavaScript types include Array, ArrayBuffer, Boolean, DataView, Date, certain Error types, Map, plain Object literals, 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 inaccessible.

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); // 0

The algorithm is used internally for data transfer between workers, IndexedDB, etc., and avoids infinite loops by tracking visited references.

Limitations: Functions, DOM nodes, and certain object metadata (e.g., property descriptors, getters/setters, prototype‑chain properties) cannot be cloned and will throw DATA_CLONE_ERR.

Conclusion

The advantages of structuredClone() are:

Reliability: predictable handling of circular references, functions, and undefined values.

Efficiency: faster deep cloning for large datasets without serialization overhead.

Simplicity: a single built‑in method replaces spread syntax, JSON tricks, or custom deep‑clone functions.

frontendperformancedeep cloningstructuredClone
Code Mala Tang
Written by

Code Mala Tang

Read source code together, write articles together, and enjoy spicy hot pot together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.