结构化克隆Structured-Clone
结构化克隆算法是 HTML5 引入的标准,最初是为了在 Web Workers 之间传递数据。Electron 的 IPC(进程间通信)底层正是基于它,在主进程(Main)和渲染进程(Renderer)这两个不同的 V8 引擎实例之间搬运数据。它的核心目标是**在不同的 JavaScript 环境中,完美重建一个相同的 JS 对象**。
#status / growing
#type / concept
[!info] related notes
- 相关笔记: json-serialization, 深拷贝, 浅拷贝 vs 深拷贝
结构化克隆 (Structured Clone)
一句话定义
structuredClone(value) 是浏览器和 Node.js 内建的深拷贝算法,支持多种原生类型和循环引用,最初为 Web Workers / postMessage 数据传递设计。
核心代码示例
// 基本用法
const original = {
date: new Date('2024-01-01'),
data: new Map([['key', 'value']]),
pattern: /test/gi,
buffer: new Uint8Array([1, 2, 3]),
nested: { arr: [1, { deep: true }] }
};
const cloned = structuredClone(original);
console.log(cloned.date instanceof Date); // true
console.log(cloned.data instanceof Map); // true
console.log(cloned.pattern instanceof RegExp); // true
// 循环引用 — 不会报错
const circular = {};
circular.self = circular;
const clonedCircular = structuredClone(circular);
console.log(clonedCircular.self === clonedCircular); // true — 正确重建
支持的类型
| 类型 | 支持 | 备注 |
|---|---|---|
| 基本类型(string, number, boolean, null, undefined, BigInt) | 支持 | |
| Array, plain Object | 支持 | |
| Date | 支持 | 克隆后仍是 Date 实例 |
| RegExp | 支持 | 克隆后仍是 RegExp 实例 |
| Map, Set | 支持 | 键和值递归克隆 |
| ArrayBuffer, TypedArray | 支持 | |
| Blob, File | 支持 | 浏览器环境 |
| ImageData | 支持 | 浏览器环境 |
| 循环引用 | 支持 | 自动处理 |
| Error (DOMException, etc.) | 部分支持 |
不支持的类型(抛出 DataCloneError)
| 类型 | 原因 |
|---|---|
| Function | 绑定当前作用域/闭包,无法跨环境传递 |
| DOM 节点 | 属于渲染进程独有 |
| Proxy | 无法序列化其拦截行为 |
| WeakMap, WeakSet | 键是弱引用,无法确定哪些该拷贝 |
| Symbol | 无法跨环境重建 |
与 JSON.parse/stringify 对比
const obj = {
date: new Date(),
regex: /test/g,
fn: () => {},
undef: undefined,
};
// JSON 方案
const jsonClone = JSON.parse(JSON.stringify(obj));
// { date: "2026-05-27T...", regex: {}, fn: 消失, undef: 消失 }
// structuredClone 方案
const scClone = structuredClone(obj);
// { date: Date实例, regex: RegExp实例 } — fn 和 undef 抛出错误(如在顶层)
| 维度 | JSON | structuredClone |
|---|---|---|
| Date | 变字符串 | 保持实例 |
| RegExp / Map / Set | 变空对象 | 保持实例 |
| undefined / Function | 静默忽略 | 顶层抛错,对象内忽略 |
| 循环引用 | 报错 | 正确处理 |
| 性能(纯数据) | 更快 | 稍慢 |
| 原型链 | 丢失 | 丢失(生成普通对象) |
| 环境支持 | 所有 | 浏览器 / Node 17+ |
实际使用场景
// Web Worker 传递数据
worker.postMessage(structuredClone(largeData));
// Electron 主进程 / 渲染进程 IPC
ipcRenderer.send('data', structuredClone(state));
// 安全的快照(不会被后续修改影响)
const snapshot = structuredClone(currentState);
边界与常见误解
- structuredClone 不保留原型链:克隆结果是普通对象,类实例上的方法会丢失。
- 不是所有环境都有:Node.js 17+ 才支持,低版本需要 polyfill。
- 性能:对纯数据对象,
JSON.parse(JSON.stringify())通常更快;需要类型保持或循环引用支持时用structuredClone。 - Electron 踩坑:IPC 发送含
Function或 DOM 节点的数据会直接DataCloneError,必须提前剥离。