Window.structuredClone() 指南
Window.structuredClone() 指南
概述
Window.structuredClone()
方法是 Web API 中的一个强大工具,用于创建 JavaScript 值的深拷贝。该方法使用结构化克隆算法,能够处理复杂的对象结构,包括循环引用,这是 JSON.parse(JSON.stringify())
无法做到的。
基本语法
structuredClone(value)
structuredClone(value, options)
参数说明
value(必需)
要克隆的对象。可以是任何可结构化克隆的类型,包括:
- 基本类型(字符串、数字、布尔值等)
- 对象和数组
- Map 和 Set
- Date 和 RegExp
- ArrayBuffer 和 TypedArray
- 以及其他可序列化的类型
options(可选)
一个包含以下属性的对象:
transfer
一个可转移对象的数组,这些对象将被移动而不是克隆到新对象中。转移后,原始对象将变得不可用。
返回值
返回原始值的深拷贝。
异常
DataCloneError
:如果输入值的任何部分不可序列化,则抛出此异常。
核心特性
1. 深拷贝能力
structuredClone()
创建的是真正的深拷贝,新对象与原始对象完全独立。
// 创建具有循环引用的对象
const original = { name: "MDN" };
original.itself = original;// 克隆它
const clone = structuredClone(original);console.assert(clone !== original); // 对象不是同一个(不同身份)
console.assert(clone.name === "MDN"); // 但它们具有相同的值
console.assert(clone.itself === clone); // 循环引用被保留
2. 支持循环引用
与 JSON 方法不同,structuredClone()
能够正确处理循环引用。
3. 支持可转移对象
可以转移某些类型的对象(如 ArrayBuffer)而不是复制它们,这样可以提高性能并确保数据安全。
使用示例
示例1:克隆简单对象
const mushrooms1 = {amanita: ["muscaria", "virosa"],
};const mushrooms2 = structuredClone(mushrooms1);mushrooms2.amanita.push("pantherina");
mushrooms1.amanita.pop();console.log(mushrooms2.amanita); // ["muscaria", "virosa", "pantherina"]
console.log(mushrooms1.amanita); // ["muscaria"]
示例2:转移 ArrayBuffer
// 创建一个 16MB 的 Uint8Array
const uInt8Array = Uint8Array.from({ length: 1024 * 1024 * 16 }, (v, i) => i);const transferred = structuredClone(uInt8Array, {transfer: [uInt8Array.buffer],
});console.log(uInt8Array.byteLength); // 0(原始缓冲区已被转移)
console.log(transferred.byteLength); // 16777216(16MB)
示例3:转移嵌套对象中的缓冲区
const arrayBuffer1 = new ArrayBuffer(1024);
const arrayBuffer2 = new ArrayBuffer(2048);const transferred = structuredClone({ x: { y: { z: arrayBuffer1, w: arrayBuffer2 } } },{ transfer: [arrayBuffer1] },
);// arrayBuffer1 被转移,arrayBuffer2 被克隆
示例4:实际应用场景 - 数据验证
// 创建 ArrayBuffer
const buffer = new ArrayBuffer(16);
const object1 = { buffer };// 克隆包含缓冲区的对象并转移它
const object2 = structuredClone(object1, { transfer: [buffer] });// 可以在克隆的对象中使用缓冲区
const int32View2 = new Int32Array(object2.buffer);
int32View2[0] = 42;
console.log(int32View2[0]); // 42// 尝试从原始缓冲区创建数组会抛出 TypeError
try {const int32View1 = new Int32Array(object1.buffer);
} catch (error) {console.error("无法访问已转移的缓冲区:", error.message);
}
浏览器兼容性
structuredClone()
方法在现代浏览器中得到了广泛支持:
- Chrome: 98+
- Firefox: 94+
- Safari: 15.4+
- Edge: 98+
该方法自 2022 年 3 月起在所有主流浏览器中可用。
与 JSON 方法的比较
特性 | structuredClone() | JSON.parse(JSON.stringify()) |
---|---|---|
循环引用 | ✅ 支持 | ❌ 不支持 |
Date 对象 | ✅ 保持类型 | ❌ 转为字符串 |
RegExp 对象 | ✅ 保持类型 | ❌ 转为空对象 |
Map/Set | ✅ 保持类型 | ❌ 转为空对象 |
ArrayBuffer | ✅ 支持 | ❌ 不支持 |
函数 | ❌ 不支持 | ❌ 不支持 |
undefined | ✅ 保持 | ❌ 被移除 |
注意事项
- 不可克隆的类型:函数、DOM 节点、Error 对象等不能被克隆
- 性能考虑:对于大型对象,克隆操作可能会消耗较多内存和时间
- 转移对象:使用转移功能时要确保原始对象不再需要,因为转移后它将变得不可用
最佳实践
- 深拷贝复杂对象:当需要完全独立的副本时使用
- Web Workers 通信:在主线程和 Worker 之间传递复杂数据
- 状态管理:在状态管理系统中创建状态的不可变副本
- 数据验证:在异步验证数据前创建安全副本
相关资源
- MDN 官方文档
- 结构化克隆算法
- 可转移对象
总结
structuredClone()
是现代 Web 开发中处理复杂数据克隆的强大工具。它解决了传统深拷贝方法的诸多限制,提供了对循环引用、特殊对象类型的完整支持,并且通过可转移对象功能优化了性能。在需要深拷贝的场景中,它应该是首选方案。