structuredClone 并非万能深拷贝工具,其设计边界明确:禁止克隆函数、CryptoKey、DOM节点、Error、WeakMap/WeakSet、undefined/Symbol及循环引用;支持Date/RegExp/Map/Set等但行为有差异;跨环境传递时仍受postMessage二次克隆限制。

structuredClone 不是万能深拷贝工具,它有明确的设计边界:不为绕过安全限制而妥协,也不为兼容旧场景而降级。它的限制不是缺陷,而是规范主动划定的“安全区”。用对地方,它高效可靠;用错对象,立刻报错。
明确禁止克隆的类型
以下类型一旦出现,整个克隆操作立即终止,抛出 DataCloneError:
- 函数(function):包括普通函数、箭头函数、class 方法等,不可序列化
- CryptoKey:W3C 明确排除,防止密钥意外泄露或绕过 extractable 控制
- DOM 节点与宿主对象:如 HTMLElement、Document、Window、ShadowRoot,属于浏览器私有状态
- Error 实例:stack、cause、内部原型链等不可枚举且无标准序列化格式
- WeakMap / WeakSet:依赖弱引用语义,无法安全重建
- undefined、Symbol(非 Symbol.for):undefined 被规范忽略,Symbol 默认不可转移
- 循环引用:不陷入死锁,而是检测到重复访问即报错,不降级处理
支持但需注意行为差异的类型
这些类型可被克隆,但结果可能与直觉不同:
-
Date / RegExp / Map / Set / ArrayBuffer 等:克隆后是新实例(
cloned.date !== original.date),但值和结构一致 -
Blob / File:内容共享底层字节,但
URL.createObjectURL()需重新调用,原 object URL 不复存在 -
FormData:不能直接克隆,需先转为键值对数组(
Array.from(formData.entries()))再克隆 - getter/setter 属性:不会执行 getter,也不会保留访问器描述符,只克隆当前可枚举值
-
冻结/密封对象:克隆后是普通对象,
Object.isFrozen()返回 false
跨环境与通信中的隐性限制
即使克隆成功,后续使用仍可能失效:
-
postMessage 传递时二次克隆:即使你先用 structuredClone 处理过对象,
worker.postMessage(obj)或window.postMessage(obj)仍会按结构化克隆规则再处理一遍——函数、Date、RegExp 等仍会被过滤或降级 -
旧环境不支持:Safari structuredClone 不存在,调用即
ReferenceError -
框架响应式代理干扰:Vue 的
reactive或 React 的 proxy 对象不可克隆,需先用toRaw或unref提取原始数据
实用规避策略
不硬扛限制,而是按场景切换策略:
-
剥离不可克隆字段:克隆前遍历对象,将
Error替换为{ name, message, stack },将CryptoKey替换为占位符或移除 -
状态与视图分离:不传 DOM 节点,改传
{ value, checked, className, dataset }等纯属性;不传new Date(),改传toISOString() -
密钥走标准流程:用
subtle.exportKey()+subtle.importKey()替代克隆,确保权限可控、格式合规 -
大二进制数据用 transfer:对
ArrayBuffer使用{ transfer: [buf] },避免内存复制,提升性能 -
兼容性兜底:检测
typeof structuredClone === 'function',否则 fallback 到JSON.parse(JSON.stringify(...))(仅限简单数据)或轻量 polyfill

















