返回
创建于
状态公开

深入理解 JavaScript 的 structuredClone

在前端开发中,我们经常遇到一个经典问题:如何安全地深拷贝一个对象? 过去我们可能会用 JSON.parse(JSON.stringify(obj)),也可能依赖 lodash.cloneDeep 这样的库。但这两种方式都有明显的局限:

  • JSON 转换:丢失 DateRegExpMap/Set 等特殊对象。
  • 第三方库:额外的依赖,可能还带来性能开销。

好消息是,现代浏览器和 Node.js 已经提供了原生的深拷贝 API —— structuredClone


什么是 structuredClone

structuredClone() 是一种 原生方法,可以创建任意 JavaScript 值的深拷贝。 语法非常简单:

js
1const clone = structuredClone(value);

其中 value 可以是对象、数组、Map、Set,甚至是带循环引用的复杂结构。


支持的类型

相比传统 JSON 方法,structuredClone 支持的类型更广泛:

  • 基本类型:string, number, boolean, null, undefined, BigInt, Symbol(作为对象属性值)
  • 内建对象:Date, RegExp, Map, Set, ArrayBuffer, Blob, File, FileList, ImageData
  • 循环引用:支持对象之间的自引用或互相引用

示例:

js
1const obj = {
2  name: "wenjie",
3  date: new Date(),
4  map: new Map([["a", 1]]),
5  set: new Set([1, 2, 3]),
6};
7
8const copy = structuredClone(obj);
9
10console.log(copy.date instanceof Date); // true
11console.log(copy.map.get("a"));         // 1
12console.log(copy.set.has(2));           // true

不支持的类型

某些值是不能被克隆的,比如:

  • 函数(Function
  • DOM 节点
  • 原型链信息(会丢失原型)
js
1const obj = {
2  fn: () => console.log("hello"),
3};
4
5structuredClone(obj); 
6// ❌ 会抛错:function is not cloneable

循环引用的处理

这是 structuredClone 的一大优势。过去遇到循环引用对象,JSON.stringify 会直接报错,而 structuredClone 可以正常工作:

js
1const a = {};
2a.self = a;
3
4const b = structuredClone(a);
5console.log(b.self === b); // true

性能表现

官方实现基于 结构化克隆算法,底层是浏览器和 Node.js 的原生实现。 相较于 JSON 或第三方库:

  • 复杂数据结构:速度更快,内存更高效
  • 简单对象:差距不大,但可读性和安全性更好

兼容性

  • 浏览器:Chrome 98+、Firefox 94+、Safari 15+
  • Node.js:v17.0 起原生支持;v16.0 需要 --experimental 标志

在老环境中,可以用 polyfill 或退回到 lodash.cloneDeep


实战案例

  1. 深拷贝 Redux 状态

    js
    1const newState = structuredClone(oldState);
  2. Web Worker 数据传输 postMessage 内部就用的结构化克隆算法,保证数据安全传递。

  3. 存储缓存

    js
    1const cache = structuredClone(data);
    2localStorage.setItem("data", JSON.stringify(cache));

总结

  • structuredClone 是现代 JS 环境下 最佳的深拷贝方案
  • 支持更多类型,能处理循环引用,性能更优。
  • 唯一要注意的是 不支持函数和 DOM 节点

如果你还在用 JSON.parse(JSON.stringify(obj)),是时候升级了!