深拷贝需按需选择:优先用structuredclone()处理内置对象和循环引用;json法简单但丢函数、date等;自定义递归函数可灵活支持特殊类型并防循环引用。

关键不是“要不要拷贝”,而是“拷贝什么、怎么拷贝、何时拷贝”。盲目深拷贝会拖慢性能,过度规避拷贝又容易引发数据污染。真正有效的策略是分层判断、按需选择。
识别哪些字段必须深拷贝
嵌套对象、数组、Map/Set、Date、RegExp 等引用类型或特殊类型,一旦被多个模块共用,修改时就会互相干扰。比如一个表单配置对象里包含 rules: [{ validator() { ... } }],函数不能被 JSON 拷贝,但若业务中只读不改,其实无需拷贝函数本身——只需隔离可变部分(如当前输入值、校验状态)。
- 必深拷贝:可变集合(
Array、Map、Set)、嵌套对象、带状态的配置项 - 可跳过:只读常量、纯函数(无闭包依赖)、
undefined或null - 需转换:
Date→ 时间戳或新Date实例;RegExp→ 重建实例
用结构化拷贝替代通用深拷贝
比起递归遍历整个对象树,按业务语义构造目标对象更轻量、更可控。例如后端返回一个用户领域对象 User,前端只需展示姓名、头像、在线状态,那就用明确字段映射生成 UserCardData,而不是把整个 User 深拷贝一遍再删减。
- DTO 转换优先用
MapStruct(Java)或zod+transform(TS),编译期生成代码,零运行时反射开销 - 前端状态派生可用
createSelector(Redux Toolkit)或computed(Vue),避免每次渲染都拷贝 - 表单编辑场景,仅对当前编辑字段做局部拷贝(如
{ ...form, profile: { ...form.profile, name: newValue } })
控制拷贝粒度与时机
高频操作中,拷贝本身可能成为瓶颈。比如每输入一个字符就深拷贝整个表单数据,或在 React useEffect 中反复拷贝 props 对象。
- 延迟拷贝:先用引用暂存,仅在提交、导出、快照等确定性节点执行拷贝
- 增量拷贝:配合
WeakMap缓存已处理子树,避免重复遍历相同对象 - 冻结只读副本:对不需要修改的拷贝结果调用
Object.freeze(),防止意外赋值,也便于 V8 优化
选对工具,不迷信“一键深拷贝”
JSON.parse(JSON.stringify()) 看似简单,实则丢数据、崩循环引用、卡大对象;lodash.cloneDeep 全面但有反射和遍历开销;现代方案更讲求平衡:
- 浏览器环境优先用
structuredClone()(支持Map/Set/Date/RegExp和循环引用) - Node.js 或需兼容旧版时,用
fast-copy—— 它对简单对象快 2 倍,对含 TypedArray 的大数据快 3 倍以上 - Java 生产环境禁用
BeanUtils.copyProperties,改用MapStruct,10000 次拷贝从 450ms 降到 8ms











