๐ง Understanding structuredClone()
in JavaScript
The structuredClone()
method provides a reliable way to create deep copies of objects, arrays, and complex data structures in JavaScript. It's designed to handle a wide range of data types, including Map
, Set
, Date
, RegExp
, and more, which older methods like JSON.parse(JSON.stringify())
struggle with.
Let's break down its usage, mechanics, pros, cons, and internals in depth.
โ๏ธ What is structuredClone()
?
-
structuredClone()
is a built-in JavaScript function introduced to make deep copying easier and more reliable. - It recursively copies all properties of an object or array, including nested structures.
- Unlike
JSON.parse(JSON.stringify())
, it supports modern JavaScript objects likeMap
,Set
,Date
,ArrayBuffer
, etc.
๐ Syntax:
const deepCopy = structuredClone(value);
Parameters:
-
value
: The value you want to deep copy. -
(Optional)
transferList
: An array of objects to transfer ownership (likeArrayBuffer
).
Return: A deeply cloned version of the input value.
๐ How structuredClone()
Works
When you call structuredClone()
, JavaScript:
- Traverses the object recursively.
- Copies primitive values directly.
-
Allocates new memory for complex types like
Object
,Array
,Map
, etc. - Skips functions (they aren't cloneable).
- Uses structured cloning algorithm, originally defined for web workers.
๐ ๏ธ Practical Examples
1๏ธโฃ Deep Copy an Array
const arr = [1, 2, [3, 4], { a: 5 }];
const deepCopy = structuredClone(arr);
// Modify the copy
deepCopy[2][0] = 999;
deepCopy[3].a = 888;
console.log(arr); // [1, 2, [3, 4], { a: 5 }] -> Original unchanged
console.log(deepCopy); // [1, 2, [999, 4], { a: 888 }]
2๏ธโฃ Deep Copy an Object
const obj = { x: 1, y: { z: 2 }, arr: [1, 2, 3] };
const deepCopy = structuredClone(obj);
deepCopy.y.z = 999;
deepCopy.arr[0] = 100;
console.log(obj); // { x: 1, y: { z: 2 }, arr: [1, 2, 3] } -> Original intact
console.log(deepCopy); // { x: 1, y: { z: 999 }, arr: [100, 2, 3] }
3๏ธโฃ Works with Complex Types
const complexObj = {
map: new Map([['key', 'value']]),
set: new Set([1, 2, 3]),
date: new Date(),
regex: /abc/i
};
const deepCopy = structuredClone(complexObj);
console.log(deepCopy.map.get('key')); // 'value'
console.log(deepCopy.set.has(2)); // true
console.log(deepCopy.date instanceof Date); // true
console.log(deepCopy.regex.test('abc')); // true
4๏ธโฃ Fails on Functions
const objWithFunc = {
greet: () => console.log('Hello'),
x: 1
};
try {
const copy = structuredClone(objWithFunc);
} catch (error) {
console.error(error.message); // Function objects are not supported
}
๐ ๏ธ Behind the Scenes
structuredClone()
implements the structured cloning algorithm, which:
- Serializes the value into a cloneable format.
- Deserializes it into a new memory location.
- Recursively processes nested structures.
๐ง Key Mechanisms
- Primitive types: Copied by value.
- Objects/arrays: Recursively cloned.
-
Special objects:
Map
,Set
,Date
,ArrayBuffer
, etc., are supported. - Unsupported: Functions, DOM nodes, and certain special objects.
โ๏ธ Pros and Cons of structuredClone()
โ Advantages (Pros)
-
True Deep Copy:
- Recursively copies nested structures.
-
Supports Complex Types:
- Works with
Map
,Set
,Date
,RegExp
,ArrayBuffer
, and other modern data types.
- Works with
-
Cleaner Syntax:
- One-liner
structuredClone(obj)
for deep copying.
- One-liner
-
Safer than JSON-based cloning:
- Preserves
Date
,RegExp
,Map
,Set
, and other objects correctly.
- Preserves
โ Disadvantages (Cons)
-
No Function Cloning:
- Functions, closures, and class instances aren't supported.
-
Performance Overhead:
- Slower than shallow copies due to recursive traversal.
-
Browser Compatibility:
- Supported in modern browsers but not in older Node.js versions.
-
Circular References:
- While supported, it adds extra complexity to the operation.
๐ Comparison with Other Methods
Feature | structuredClone() | JSON.parse(JSON.stringify()) | Lodash.cloneDeep() |
---|---|---|---|
Deep Copy | โ Yes | โ Yes | โ Yes |
Functions Supported | โ No | โ No | โ Yes |
Handles Circular References | โ Yes | โ No | โ Yes |
Supports Dates | โ Yes | โ No | โ Yes |
Supports RegExp | โ Yes | โ No | โ Yes |
Supports Map/Set | โ Yes | โ No | โ Yes |
Performance | โก Fast | โก Faster (for simple objects) | ๐ข Slower |
Browser Support | ๐ Modern Only | ๐ Universal | ๐ Requires Dependency |
๐งช Performance Insights
While structuredClone()
is efficient, it is slower than shallow copying methods like the spread operator.
๐ ๏ธ Benchmark Test
const obj = { a: 1, b: { c: [1, 2, 3] } };
// Shallow Copy
console.time('Shallow Copy');
const shallow = { ...obj };
console.timeEnd('Shallow Copy');
// Deep Copy with JSON
console.time('JSON Clone');
const jsonClone = JSON.parse(JSON.stringify(obj));
console.timeEnd('JSON Clone');
// Deep Copy with structuredClone
console.time('structuredClone');
const deepClone = structuredClone(obj);
console.timeEnd('structuredClone');
Expected Output (Approx.):
-
Shallow Copy
: ~0.1 ms -
JSON Clone
: ~0.3 ms -
structuredClone
: ~0.5 ms
Explanation:
- Shallow copy: Just copies references.
- JSON clone: Serializes and deserializes.
- structuredClone: Performs more complex logic to handle various types.
โ ๏ธ Edge Cases and Limitations
Functions:
Functions are not cloneable. Attempting to clone them results in aDataCloneError
.DOM Elements:
structuredClone()
doesn't support cloning DOM nodes likeHTMLElement
orWindow
.Prototypes Lost:
Custom prototypes are not preserved, resulting inObject
prototypes.Symbol Properties:
Symbols as object properties are ignored.
๐ ๏ธ Alternative Custom Deep Copy (Manual)
For educational purposes, here's a manual deep clone implementation:
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (Array.isArray(obj)) {
return obj.map(deepClone);
}
if (obj instanceof Map) {
return new Map([...obj.entries()].map(([key, value]) => [deepClone(key), deepClone(value)]));
}
if (obj instanceof Set) {
return new Set([...obj].map(deepClone));
}
if (obj instanceof Date) {
return new Date(obj);
}
if (obj instanceof RegExp) {
return new RegExp(obj.source, obj.flags);
}
const clonedObj = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key]);
}
}
return clonedObj;
}
Usage:
const obj = { a: 1, b: { c: 2 }, d: new Date(), e: new Set([1, 2, 3]) };
const deepCopied = deepClone(obj);
console.log(deepCopied);
๐ Conclusion
structuredClone()
is a powerful, modern, and reliable way to create deep copies of arrays and objects without the quirks and limitations of JSON-based approaches. While it doesn't support functions or classes, it remains an ideal solution for most data structures.
When performance isn't critical and compatibility is guaranteed, structuredClone()
should be your go-to method for deep cloning in JavaScript. โ
Top comments (0)