手动实现深拷贝处理循环引用的核心是用weakmap缓存源对象到副本的映射,提前识别复用;需分类处理类型、显式传递独立cache;现代环境优先使用structuredclone()。

手动实现深拷贝时处理循环引用,核心不是避免递归,而是提前识别并复用已生成的副本——用 WeakMap 做映射缓存,是最轻量、安全且符合规范的做法。
用 WeakMap 缓存源对象到副本的映射
WeakMap 的键是对象引用,不阻止垃圾回收,适合跟踪临时拷贝关系。每次进入新对象前,先查它是否已在缓存中:
- 查到了,直接返回对应副本,中断递归链
- 没查到,立即创建空对象(或数组等),存入 WeakMap,再继续遍历属性
- 这样即使 a → b → a 形成环,第二次遇到 a 也能命中缓存,跳出无限递归
按类型分层处理,不一概递归
不是所有值都需要进 WeakMap 或走递归逻辑。要分类判断:
- null、undefined、string、number、boolean、symbol、bigint:直接返回,不参与缓存
- Date、RegExp、ArrayBuffer、TypedArray:用 new 构造新实例,然后存入 WeakMap(防重复构造)
- Map / Set:新建后递归拷贝键和值,键也可能是对象,同样走 WeakMap 检查
- 普通对象或数组:先占位({} 或 []),立刻缓存,再逐个赋值
缓存必须显式传递,不能默认初始化
常见错误是把 cache 写成函数默认参数:function deepClone(obj, cache = {})。这会导致多次调用共用同一个 cache,跨调用污染数据。
- 正确做法:cache 默认为 null,首次调用时初始化为 new WeakMap()
- 后续所有递归调用都显式传入当前 cache 实例
- 确保每次 deepClone 调用拥有独立缓存空间
现代环境优先用 structuredClone
Chrome 98+、Node.js 18.15+/20.6+ 已稳定支持 structuredClone(),它内置循环检测、支持 Date/Map/Set/RegExp 等类型,一行代码即可。
- 优点:语义准确、性能可靠、无需维护
- 限制:不支持 function、Symbol、undefined、Error、DOM 节点等
- 适用场景:纯数据结构拷贝,尤其是含循环引用或多种内置对象时
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











