递归实现深拷贝需逐层判断类型并构造新结构,关键在于精准区分引用类型、处理循环引用、保留原型链及完整属性(含Symbol和不可枚举属性),且数组判断必须优先于普通对象。

递归实现深拷贝,本质是逐层判断类型、构造新结构、再对每个子值继续调用自身。关键不在“多维”,而在正确处理所有引用类型和边界情况。
先判断类型,再分路径处理
不能只用 typeof,它对数组、null、Date 都返回 "object"。要用更精确的方式区分:
-
null 单独判断(
obj === null) - 基本类型(string/number/boolean/undefined/symbol/bigint)直接返回
-
Array:用
Array.isArray(obj)判断,创建空数组[] -
Date / RegExp:用
instanceof创建对应新实例 -
普通对象:用
Object.create(Object.getPrototypeOf(obj))保留原型链
必须处理循环引用
如果对象里有 self-reference(比如 obj.a = obj),递归会无限下去。解决方案是用 WeakMap 缓存已处理过的对象:
- 每次进入函数,先查
hash.has(obj),存在就直接返回缓存结果 - 新建副本后,立刻
hash.set(obj, cloneObj) - WeakMap 不阻止垃圾回收,安全且轻量
别漏掉 Symbol 属性和不可枚举属性
for...in 只遍历可枚举自有属性,会丢掉 Symbol 键和 Object.defineProperty 设置的不可枚举属性:
立即学习“Java免费学习笔记(深入)”;
- 用
Object.getOwnPropertySymbols(obj)获取所有 Symbol 键 - 用
Object.getOwnPropertyNames(obj)获取所有自有属性名(含不可枚举) - 对每个 key,用
Object.getOwnPropertyDescriptor(obj, key)读取描述符,再用Object.defineProperty(cloneObj, key, descriptor)复制
数组要放在对象前面判断
因为 Array instanceof Object 是 true,如果先判断 object 再判断 array,数组会被当成普通对象处理,导致 [] 变成 {}:
- 顺序必须是:
Array.isArray→obj instanceof Date→obj instanceof RegExp→ 其他 object - 这样能确保数组被正确识别并初始化为
[]


















