How to Deep Copy in JavaScript with structuredClone
The structuredClone() method is a native JavaScript
utility designed to create deep copies of complex values, eliminating
the need for third-party libraries like Lodash or problematic hacks like
JSON.parse(JSON.stringify()). This article explains how
structuredClone() operates under the hood using the
structured clone algorithm, details the data types it supports,
demonstrates how it handles circular references and transferable
objects, and outlines its key limitations.
What is structuredClone?
structuredClone() is a globally available function in
modern web browsers, Node.js (v17+), and Deno. It accepts a target value
and returns a complete, independent duplicate where nested objects,
arrays, and other data structures are duplicated in memory rather than
copied by reference.
const original = { name: "Alice", details: { age: 30 } };
const copy = structuredClone(original);
copy.details.age = 31;
console.log(original.details.age); // 30 (unaffected)How the Algorithm Works
Under the hood, structuredClone() uses the
Structured Clone Algorithm, an internal HTML standard
mechanism originally built for messaging across Web Workers,
postMessage(), and IndexedDB.
- Recursive Graph Traversal: The algorithm traverses the entire input structure recursively, inspecting every property and value.
- Memory Allocation: Instead of copying pointer references, it allocates new memory locations for every encountered composite structure (such as Objects, Arrays, Maps, and Sets).
- Graph Mapping for Circular References: The algorithm keeps an internal reference map of previously traversed objects. If it encounters an object it has already cloned in the current traversal path, it points to the newly created clone rather than recursively expanding forever. This natively prevents infinite recursion errors on circular references.
const circularObj = { name: "Loop" };
circularObj.self = circularObj;
const clonedCircular = structuredClone(circularObj);
console.log(clonedCircular.self === clonedCircular); // true
console.log(clonedCircular.self === circularObj); // falseSupported Data Types
Unlike JSON serialization, structuredClone() preserves
many built-in JavaScript types:
- Primitives: String, Number, BigInt, Boolean,
null,undefined. - Collections:
Map,Set, and regularArrayinstances. - Objects: Standard Object literals,
Date, andRegExpobjects (retaining their behavior and properties). - Binary Data:
ArrayBuffer,TypedArrayviews (Uint8Array,Float64Array, etc.), andDataView. - Web APIs:
Blob,File,FileList, andImageData.
Transferable Objects
structuredClone() accepts an optional second argument
allowing you to transfer ownership of specific resources instead of
copying their bytes.
const uInt8Array = new Uint8Array(1024 * 1024); // 1MB buffer
const clone = structuredClone(uInt8Array, { transfer: [uInt8Array.buffer] });
console.log(uInt8Array.byteLength); // 0 (detached/neutered)
console.log(clone.byteLength); // 1048576 (transferred to clone)Transferring is memory-efficient for large binary payloads because it moves the underlying buffer reference instantly without duplicating memory allocation.
Limitations and Unsupported Types
While powerful, structuredClone() has explicit
limitations:
- Functions: Attempting to clone a function or method
throws a
DataCloneErrorDOMException. - DOM Nodes: HTML elements and document nodes cannot be cloned.
- Prototypes: Prototype chains are discarded. Cloned instances of custom classes become plain JavaScript objects.
- Property Descriptors: Getters, setters, and
read-only flags (
Object.defineProperty) are flattened; only the resulting values are copied. - Symbols: Symbol-keyed properties and primitive Symbol values cannot be cloned.