DEV Community

VivekSinh Rajput
VivekSinh Rajput

Posted on

structuredClone() how to use it???

๐Ÿง  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 like Map, Set, Date, ArrayBuffer, etc.

๐Ÿ“œ Syntax:

const deepCopy = structuredClone(value);
Enter fullscreen mode Exit fullscreen mode

Parameters:

  • value: The value you want to deep copy.
  • (Optional) transferList: An array of objects to transfer ownership (like ArrayBuffer).

Return: A deeply cloned version of the input value.


๐Ÿ” How structuredClone() Works

When you call structuredClone(), JavaScript:

  1. Traverses the object recursively.
  2. Copies primitive values directly.
  3. Allocates new memory for complex types like Object, Array, Map, etc.
  4. Skips functions (they aren't cloneable).
  5. 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 }]
Enter fullscreen mode Exit fullscreen mode

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] }
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ› ๏ธ Behind the Scenes

structuredClone() implements the structured cloning algorithm, which:

  1. Serializes the value into a cloneable format.
  2. Deserializes it into a new memory location.
  3. 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)

  1. True Deep Copy:
    • Recursively copies nested structures.
  2. Supports Complex Types:
    • Works with Map, Set, Date, RegExp, ArrayBuffer, and other modern data types.
  3. Cleaner Syntax:
    • One-liner structuredClone(obj) for deep copying.
  4. Safer than JSON-based cloning:
    • Preserves Date, RegExp, Map, Set, and other objects correctly.

โŒ Disadvantages (Cons)

  1. No Function Cloning:
    • Functions, closures, and class instances aren't supported.
  2. Performance Overhead:
    • Slower than shallow copies due to recursive traversal.
  3. Browser Compatibility:
    • Supported in modern browsers but not in older Node.js versions.
  4. 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');
Enter fullscreen mode Exit fullscreen mode

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

  1. Functions:

    Functions are not cloneable. Attempting to clone them results in a DataCloneError.

  2. DOM Elements:

    structuredClone() doesn't support cloning DOM nodes like HTMLElement or Window.

  3. Prototypes Lost:

    Custom prototypes are not preserved, resulting in Object prototypes.

  4. 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;
}
Enter fullscreen mode Exit fullscreen mode

Usage:

const obj = { a: 1, b: { c: 2 }, d: new Date(), e: new Set([1, 2, 3]) };
const deepCopied = deepClone(obj);
console.log(deepCopied);
Enter fullscreen mode Exit fullscreen mode

๐Ÿš€ 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)