不能直接对 reactive 对象深拷贝,需走「解包→拷贝→重包」三步:先用 toRaw 安全解包,再用 structuredClone 或 cloneDeep 拷贝,最后按需用 reactive 重包;避免直接赋值或解构破坏响应式。

不能直接对 reactive 对象做深拷贝,因为它的底层是 Proxy 实例,而 Proxy 对象不可序列化、不可递归遍历。强行调用 structuredClone、JSON.stringify 或 lodash.cloneDeep 会报错或返回空/不完整数据。真正要做的不是“绕过 Proxy”,而是“先离开它,再回来”——即走通「解包 → 拷贝 → 重包」三步闭环。
先用 toRaw 安全解包原始数据
toRaw() 是 Vue 官方提供的标准解包工具,能完整剥离 reactive 对象及其所有嵌套层级的 Proxy 包装,返回纯粹的普通 JavaScript 对象(包括 Date、Map、Set、RegExp 等原生类型也会保留)。
- 对顶层 reactive:直接
const raw = toRaw(state) - 对嵌套 reactive(如
state.profile = reactive({ ... })):toRaw会自动递归解包整个结构,无需手动处理子级 - 对 ref 类型数据,优先用
unref(),它能统一处理 ref / reactive / 普通值,再配合toRaw更稳妥
选合适方式做纯净深拷贝
解包后得到的是普通对象,此时可放心使用任意深拷贝方法,但需按需选择:
Orderly React SDK 钩子使用参考指南,包括 useOrderEntry、usePositionStream、useOrderbookStream、useCollateral 等。
- 现代环境(Chrome 98+、Edge 98+、Safari 15.4+):首选
structuredClone(raw),支持 Map、Set、Date、RegExp、ArrayBuffer 等,且性能好、无依赖 - 需兼容旧浏览器或定制逻辑(如过滤敏感字段、跳过 Symbol 键、替换特定值):封装轻量递归函数,内部明确跳过函数、undefined、Symbol,并用 WeakMap 处理循环引用
- 项目已引入 lodash-es:按需导入
import { cloneDeep } from 'lodash-es',避免全量引入;注意它不识别 Vue 的 Proxy,所以必须在toRaw后调用 - 避免
JSON.parse(JSON.stringify()):会丢失函数、undefined、Symbol、Date、RegExp,且无法处理循环引用
按需重新包裹为响应式
拷贝结果默认是普通对象,是否需要响应式,取决于后续用途:
立即学习“前端免费学习笔记(深入)”;
- 仅用于一次性提交(如 API 请求体):直接用
const submitData = { ...toRaw(state) }或structuredClone(toRaw(state)),操作它完全安全,不影响源数据 - 需要新副本也具备响应式能力:用
reactive(cloned)包裹,得到一个独立的、全新代理的新响应式对象 - 若原数据含
ref字段(如count: ref(0)),解包时需先取.value,拷贝后再用ref()单独重包该字段
特别注意解构与赋值陷阱
即使完成深拷贝,若后续操作不当,仍可能意外破坏响应连接:
- 不要把拷贝结果直接赋给原 reactive 变量:
state = cloned—— 这会丢弃 Proxy,彻底失活 - 不要解构拷贝后的对象再赋值:
const { name } = cloned; state.name = name是安全的,但state = { ...cloned }就不行 - 修改源数据时,确认操作目标是
state.xxx而非某个已解构的局部变量,后者只是快照,改了也不触发更新

















