structuredClone 无法处理 Proxy 对象是设计限制,会抛出 DataCloneError;因其无识别机制、无重建能力且规范明确禁止,正确做法是克隆 target 后手动重建 Proxy 或封装为可克隆结构。

structuredClone 无法处理 Proxy 对象,这是设计限制,不是 bug。它会直接抛出 DataCloneError,因为 Proxy 的拦截逻辑(get/set/apply 等)绑定在特定实例上,且没有 API 能读取其 target 或 handler,属于不可逆封装。
为什么 structuredClone 一定失败
Proxy 在 structuredClone 中被明确排除在可克隆类型之外:
-
无识别机制:
Object.prototype.toString.call(proxy)返回[object Object],无法区分普通对象与 Proxy - 无重建能力:没有标准方法获取 proxy 的 handler 和 target,因此无法构造新 proxy
-
规范禁止:HTML 结构化克隆算法未将 Proxy 列入支持类型列表,任何尝试都会触发
DataCloneError
正确应对方式:避免拷贝,改为重建
不要试图“修复” structuredClone 去支持 Proxy,而应从数据建模层面规避:
-
只克隆原始数据源(target):若 proxy 仅用于响应式包装,先用
proxyTarget(需你持有或暴露该引用)获取原始对象,再对它调用structuredClone -
手动重建 proxy:用相同的 handler 和克隆后的 target 构造新 proxy:
new Proxy(structuredClone(target), handler) -
封装为可克隆结构:把 proxy 相关逻辑抽离成配置对象(如
{ type: 'reactive', data: {...}, options: {...} }),克隆该配置,再按需初始化
哪些方案无效,务必避开
以下常见思路在实际中均不可靠:
-
JSON.stringify + parse:Proxy 序列化后变为空对象
{},完全丢失行为和数据 - lodash.cloneDeep 或手写递归:同样无法识别 Proxy,更无法还原 trap;可能静默降级或无限循环
- try/catch 后 fallback:structuredClone 报错后,降级方案(如 JSON)无法恢复 Proxy 语义,业务逻辑大概率中断
- 代理对象自身实现 clone 方法:Proxy 实例不能添加自有属性或方法(除非 handler 显式允许),不可行
长期建议:设计时就远离 Proxy 拷贝需求
Proxy 本质是运行时行为增强,不是数据载体。在需要深拷贝的场景(如状态快照、跨线程传输、表单回滚),应确保参与克隆的对象是纯数据结构:
- 将响应式逻辑与数据分离,例如使用
ref(value)包装值,但克隆时只操作value - 在框架层(如 Vue、Solid)中,利用其提供的
toRaw或store解包能力获取可序列化数据 - 若必须保留代理语义,改用类封装 + 显式
clone()方法,把 Proxy 创建逻辑内聚在类内部


















