手写递归深拷贝的关键是精准类型分发、递归构建新结构、用weakmap拦截循环引用;需区分null/基本类型/date/regexp/数组/对象等,对特殊内置对象按规则复制,避免原型继承与无限递归。

手写递归深拷贝的关键是:区分数据类型、避免循环引用、正确处理特殊对象(如 Date、RegExp、Map、Set 等),并为对象和数组分别递归创建新结构。
基础判断与类型分发
先用 Object.prototype.toString.call() 精确识别类型,不能只靠 typeof 或 Array.isArray() —— 后者对类数组、TypedArray 无效,前者对对象/数组都返回 "object"。
核心判断逻辑如下:
-
null 直接返回(注意
typeof null === "object",需单独处理) - 基本类型(string / number / boolean / bigint / symbol / undefined)直接返回,不递归
-
Date / RegExp 实例,用构造函数新建副本:
new Date(obj) / new RegExp(obj) - Array / Object 进入递归分支;其他内置对象(如 Map、Set、TypedArray)按需支持
递归复制对象和数组
对普通对象和数组,需新建空容器,再遍历键或索引,递归拷贝每个值:
- 数组:用
Array.from(arr, item => deepClone(item))或map+ 递归 - 对象:用
Object.keys(obj).reduce(...)或for...in+hasOwnProperty遍历自有属性 - 注意保留原型链?一般深拷贝不继承原型(即使用
{}和[]创建),若需继承可用Object.create(Object.getPrototypeOf(obj))
防止循环引用(关键!)
若对象内部存在自引用(如 a.b = a),不加控制会无限递归导致栈溢出。解决方案是维护一个 WeakMap 缓存已拷贝过的源对象及其对应副本:
- 每次进入递归前,先查 WeakMap:存在则直接返回缓存副本
- 不存在则新建目标({} 或 []),立即存入 WeakMap(源 → 副本),再递归填充属性
- WeakMap 适合此处:键是对象,且不阻止垃圾回收,安全又高效
可选:支持更多内置类型
实际项目中常需兼容 Map、Set、TypedArray、Error、Promise 等。处理原则一致:
-
Map:新建
new Map(),遍历map.entries(),递归拷贝 key 和 value -
Set:新建
new Set([...set].map(deepClone)) -
TypedArray(如 Uint8Array):用
constructor和slice()创建副本:new obj.constructor(obj) -
Error:手动提取
message、name、stack构造新实例 - Function:通常不拷贝(函数是引用,且无法可靠序列化),直接返回原引用或抛出提示
不复杂但容易忽略。核心就三点:类型精准分发、递归填充结构、WeakMap 拦截循环引用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











