手动递归实现深拷贝需先判断typeof obj === 'object' && obj !== null,再用weakmap处理循环引用,分类构造array、date、regexp、map、set及普通对象,保留属性描述符与原型链。

手动递归实现深拷贝,核心是正确处理循环引用、特殊类型(Date、RegExp、Map、Set 等)、不可枚举属性和原型链继承,同时避免对 null、undefined、原始值做多余递归。
识别并拦截基础类型与 null/undefined
深拷贝只对对象(包括数组、函数、日期等)有意义。必须在递归入口快速返回原始值,否则会报错或逻辑错乱:
- typeof obj === 'object' && obj !== null 是进入递归的必要前提
- 直接用 switch 或 if 判断 typeof 结果:'string'、'number'、'boolean'、'symbol'、'bigint'、'undefined'、'function' 都应原样返回
- 特别注意 typeof null === 'object',所以必须先判 null
用 WeakMap 记录已拷贝对象,解决循环引用
当对象 A 的某个属性指向自身,或 A→B→A 构成环时,不加控制的递归会栈溢出。WeakMap 可以安全地缓存源对象到目标对象的映射:
- 每次进入递归前,先查 weakMap.has(obj),存在则直接返回对应拷贝结果
- 创建新对象后(如 {} 或 new obj.constructor()),立即 weakMap.set(obj, result)
- WeakMap 不阻止垃圾回收,适合临时缓存,比 Map 更安全
按构造器类型分发处理,覆盖常见内置对象
不能统一用 JSON.parse(JSON.stringify())(丢失函数、undefined、Date 格式错误),也不能全用 for...in(漏掉 Symbol 属性、不可枚举属性、原型方法)。应分类处理:
- Array:Array.isArray(obj) → result = [],再递归拷贝每一项
- Date / RegExp:new obj.constructor(obj) 即可(Date 和 RegExp 支持传参构造)
- Map / Set:new Map([...obj.entries()]) 或 new Set([...obj.values()]),entries/values 内部已递归处理键值
- 普通对象({}):用 Object.getOwnPropertyDescriptors 获取所有自有属性(含 getter/setter、writable/enumerable/configurable),再用 Object.defineProperties 创建新对象
保留原型但不拷贝原型链上的属性
深拷贝目标是复制“值”,不是模拟继承关系。但某些场景需要保持 constructor 和 instanceof 行为,可通过 Object.setPrototypeOf 实现:
- 对普通对象,result = Object.create(Object.getPrototypeOf(obj))
- 之后再 defineProperties,确保原型方法不被误拷为数据属性
- 注意:不要递归拷贝 Object.prototype 上的属性(如 toString),它们属于共享行为
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











