javascript深拷贝需解决循环引用和特殊类型处理两大问题:用weakmap检测循环引用,对date、regexp、map、set等特殊类型显式构造,并通过getprototypeof、getownpropertydescriptors等api还原原型链与不可枚举属性。

JavaScript深拷贝遇到循环引用会直接报错,特殊类型(如Date、RegExp、Map、Set、Function等)若不单独处理,拷贝结果往往失真或丢失。解决这两个问题需要自定义逻辑,不能只靠JSON.parse(JSON.stringify())或简单递归。
检测并跳过循环引用
核心思路是记录已遍历过的对象及其对应的新对象,在递归过程中查表:若当前对象已被处理过,就直接返回对应的新对象,避免无限递归。
- 用WeakMap存储原始对象 → 拷贝后对象的映射(WeakMap适合避免内存泄漏)
- 每次进入对象前先查表,命中则返回缓存结果
- 未命中则新建对象,立即存入WeakMap,再递归处理属性
逐类识别与构造特殊类型
Object和Array只是基础,Date、RegExp、Map、Set、TypedArray、Error、Promise等都有独立的构造方式和内部属性,需显式判断并还原。
-
Date:用
new Date(obj.getTime())或new Date(obj.toString()) -
RegExp:用
new RegExp(obj.source, obj.flags)(注意global/unicode等标志) -
Map/Set:新建实例,遍历
obj.entries()或obj.values()逐项拷贝键值 -
TypedArray:用
obj.constructor.from(obj)或new obj.constructor(obj) - Function:通常不拷贝(保留原引用),若需“复制”,只能字符串化+eval(不推荐)或明确业务场景处理
保持原型链与不可枚举属性
单纯用Object.assign或展开运算符会丢失原型和不可枚举属性(如Object.defineProperty定义的)。可靠做法是:
- 用
Object.getPrototypeOf(obj)获取原型,拷贝后用Object.setPrototypeOf(newObj, copiedProto)恢复 - 用
Object.getOwnPropertyDescriptors(obj)获取所有属性描述符(含get/set/configurable/enumerable) - 用
Object.defineProperties(newObj, descriptors)批量定义,确保访问器、冻结状态等被还原
可选:支持自定义拷贝逻辑
为应对业务中自定义类(如Model、EventEmitter),可预留toJSON或[Symbol.clone]钩子。
- 若对象有
toJSON方法,优先调用它获取可序列化数据再拷贝 - 若实现
[Symbol.clone](),直接执行该方法并返回结果 - 也可传入配置对象,指定某类构造器的克隆函数,例如
{ Date: () => new Date() }
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











