深拷贝需保持原型继承关系,关键在于使新对象的__proto__指向原对象原型;structuredclone是现代首选方案,兼容旧环境需手动重建原型链并注意循环引用处理。

深拷贝时保持原型继承关系,关键不是“复制原型上的属性”,而是让新对象的 __proto__ 指向原对象的原型,从而维持 instanceof、方法调用、属性查找等行为完全一致。
为什么普通深拷贝会丢失原型
JSON.parse(JSON.stringify())、Lodash 的 cloneDeep、甚至部分手写递归实现,默认都只处理可枚举自有属性,并用 {} 或 Object.assign({}, obj) 创建目标对象——这类方式生成的对象原型固定为 Object.prototype,原始构造器和继承链全部丢失。
结果是:copy instanceof MyClass 变成 false,copy.method() 报错,响应式系统(如 Vue)也可能失效。
现代首选:structuredClone(保留原型链)
Chrome 98+、Firefox 94+、Node.js 17.0+ 原生支持 structuredClone(),它对多数内置类型(Date、RegExp、Map、Set、ArrayBuffer 等)自动保留原型:
- 拷贝后的
new Date()仍是Date实例,instanceof Date === true - 支持循环引用,内部用图遍历,不爆栈
- 不执行 getter、不遍历原型链,安全性更高
- 不支持函数、undefined、Symbol、Promise、WeakMap/WeakSet —— 这是规范限制,非 bug
用法极简:const copy = structuredClone(original);
兼容旧环境:手动重建原型关系
若需支持 Node.js
- 用
Object.getPrototypeOf(obj)获取原对象原型 - 用
Object.create(proto)创建空对象,其__proto__指向该原型 - 再用
Object.getOwnPropertyDescriptors(obj)获取所有自有属性(含 getter/setter、不可枚举属性、writable 等) - 递归深拷贝每个属性值,最后用
Object.defineProperties(newObj, descriptors)批量定义 - 用
WeakMap缓存已拷贝对象,防止循环引用无限递归
注意:不要直接赋值 copy.__proto__ = obj.__proto__,在严格模式或冻结对象上可能失败;也不要依赖 obj.constructor,因箭头函数、Object.create(null) 等场景下 constructor 不可靠。
设计层面规避依赖原型的硬伤
如果深拷贝频繁成为瓶颈或风险点,可从架构上降低对原型链的强依赖:
- 用鸭子类型代替
instanceof:检查obj.getDate是否为函数,而非obj instanceof Date - 把核心逻辑抽成纯函数,接收原始数据(如时间戳、正则字符串),而非实例
- 自定义类提供
toJSON()和静态fromJSON()方法,控制序列化/反序列化行为 - 避免在原型上挂载闭包状态或异步上下文,防止拷贝后逻辑错乱
上线前务必加断言验证:copy instanceof OriginalClass、typeof copy.method === 'function'、Object.getPrototypeOf(copy) === OriginalClass.prototype。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











