structuredclone()是原生深拷贝方法,支持map、set、date、regexp等json不支持的类型,能处理循环引用,性能更优;但不支持函数、symbol、dom节点及旧浏览器。

structuredClone() 是现代浏览器中用于安全、高效地创建对象深度副本的原生方法,特别适合在主线程与 Web Worker 之间传递复杂状态(如嵌套对象、数组、Map、Set、Date、RegExp 等),避免引用共享和意外修改。它比 JSON 序列化更强大(支持更多类型),也比手动递归克隆更可靠、更快速。
为什么不用 JSON.parse(JSON.stringify())?
JSON 方式有明显缺陷:
- 丢失函数、undefined、Symbol、BigInt、Map、Set、Date(变成字符串)、RegExp(变成空对象)、TypedArray(可能出错)等类型
- 无法处理循环引用,直接抛错
- Date 和 RegExp 等对象失去原型行为和方法
- 性能较差,尤其对大对象需两次序列化/解析
如何在 Web Worker 中正确使用 structuredClone()
structuredClone() 在主线程和 Worker 线程中均可用(Chrome 98+、Firefox 97+、Safari 15.4+)。关键点是:它必须作用于可结构化克隆的对象(即符合 结构化克隆算法 规范的值)。
- ✅ 支持:Object、Array、Map、Set、Date、RegExp、Blob、File、ImageData、TypedArray、DataView、Error(部分浏览器)、null、布尔、数字、字符串、BigInt(需开启 flag 或较新版本)
- ❌ 不支持:function、Promise、window、document、DOM 节点、WeakMap、WeakSet、代理对象(Proxy)、生成器(Generator)
用法极简:
const original = { user: { id: 1, name: "Alice" }, tags: new Set(["web", "worker"]) };
const cloned = structuredClone(original); // 完整深拷贝,tags 仍是 Set 实例
配合 postMessage 传递状态(推荐方式)
structuredClone() 本身不负责跨线程传输,但它的输出天然适配 postMessage() 的结构化克隆机制 —— 实际上,现代浏览器调用 postMessage(data) 时,底层就自动使用了结构化克隆算法。因此你通常无需显式调用 structuredClone() 再传参,直接传原始对象即可:
// 主线程
const state = {
config: { timeout: 5000 },
cache: new Map([["key", { ts: Date.now() }]]),
pattern: /test/gi
};
worker.postMessage(state); // ✅ 浏览器自动深克隆并传输
// Worker 线程(onmessage 中)
self.onmessage = ({ data }) => {
console.log(data.config.timeout); // 5000
console.log(data.cache instanceof Map); // true
console.log(data.pattern.test("TEST")); // true
};
⚠️ 注意:若你在主线程中先修改了原对象,再 postMessage,不影响 Worker 收到的数据 —— 因为传输的是独立副本。
何时需要手动调用 structuredClone()?
典型场景包括:
- 在 Worker 内部对收到的状态做预处理后再保存或转发:避免后续误改影响其他逻辑
- 从 Worker 向主线程回传一份“快照”而非实时引用(虽然主线程也无法持有 Worker 内对象引用,但克隆可确保状态隔离)
- 实现本地状态缓存或 undo/redo 栈:例如保存上一版配置供回滚
// Worker 内部示例
let currentState;
self.onmessage = ({ data }) => {
currentState = structuredClone(data); // 显式保留原始快照
processState(currentState);
};
function saveSnapshot() {
const snapshot = structuredClone(currentState);
history.push(snapshot); // 用于撤销
}
兼容性与降级建议
若需支持旧浏览器(如 Safari
function safeClone(obj) {
if (typeof structuredClone === 'function') {
try {
return structuredClone(obj);
} catch (e) {
console.warn('structuredClone failed, falling back to JSON');
}
}
// 降级:仅适用于纯 JSON 友好数据(无函数、日期、Map 等)
return JSON.parse(JSON.stringify(obj));
}
注意:降级方案无法还原非 JSON 类型,应结合业务约束判断是否可接受 —— 若状态含 Map/Set/Date,建议直接要求现代环境,或使用第三方库(如 lodash.cloneDeep,但体积大、Worker 中需额外打包)。











