优先用 structuredclone() 实现深拷贝,它支持主流类型且语法简洁;手写递归需处理 null、date、regexp、map/set、循环引用等关键分支;生产环境推荐 lodash.clonedeep 兜底;避免无脑 json 方法。

在复杂状态树更新时用深拷贝,核心目标是确保新旧状态完全隔离,避免意外修改原始数据。这不是简单“复制一下”,而是要兼顾正确性、性能和可维护性。
优先用 structuredClone() 处理主流类型
现代浏览器和 Node.js 18.15+/20.6+ 已稳定支持 structuredClone(),它能正确处理 Date、RegExp、Map、Set、ArrayBuffer、TypedArray、循环引用等,且语法极简:
- 直接调用:
const nextState = structuredClone(currentState); - 适合大多数 Redux/Vuex/Zustand 场景中的纯数据状态(不含函数、Symbol、DOM 节点)
- 注意:遇到 function、undefined、Error、Promise 或不可枚举属性会抛
DataCloneError,需提前过滤或降级处理
手写递归深拷贝要守住关键分支
当状态含自定义类、getter/setter、或需兼容老旧环境时,手写递归更可控。重点不是“写递归”,而是精准识别并分治每种类型:
-
null 和 undefined:必须单独判断,
typeof null === 'object'是经典陷阱 -
Date / RegExp:用构造函数重建,如
new Date(obj)、new RegExp(obj) -
Array / Object:用
Array.isArray()和obj.constructor保持原型链 -
Map / Set:不能只展开键值,要
new Map([...obj.entries()].map(([k, v]) => [k, deepClone(v)])) -
循环引用:必须用
WeakMap缓存已拷贝对象,否则栈溢出
生产环境推荐 lodash.cloneDeep 做兜底
自己实现易漏边界,尤其在涉及 Error、Promise、BigInt、稀疏数组等边缘情况时。Lodash 的 _.cloneDeep 经过多年打磨,覆盖绝大多数真实业务状态结构:
- 安装:
npm install lodash,按需引入:import { cloneDeep } from 'lodash' - 它保留 function 引用(浅拷贝)、不丢 undefined、支持自定义克隆逻辑(通过
customizer参数) - 适用于表单状态、配置树、编辑器 AST 等深层嵌套且类型混杂的场景
避免无脑 JSON 方法,除非你确认数据足够干净
JSON.parse(JSON.stringify(state)) 表面简洁,但实际风险高:
- Date 变字符串、RegExp 变空对象、函数和 undefined 直接消失
- 遇到循环引用立即崩溃,无法用于有父子/引用关系的状态(如树形菜单、带 parent 指针的节点)
- 仅建议用于临时调试、快照导出、或明确约束为“仅含字符串/数字/布尔/纯对象/数组”的轻量配置
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











