深拷贝必须保留原型链,否则导致instanceof失效和方法丢失;优先用structuredclone,兼容环境需手动重建原型或改用鸭子类型等策略。

深拷贝时原型链丢失不是小问题,而是直接影响方法调用、实例判断和继承行为的硬伤。JSON.parse(JSON.stringify()) 会把所有对象降级为 plain Object,导致 obj instanceof MyClass 返回 false、原型上定义的方法全部不可用。生产环境必须保证拷贝后仍能正确识别类型、调用原型方法、维持继承关系。
优先使用 structuredClone(现代浏览器 & Node.js 17+)
这是目前最接近“开箱即用”的原生方案,对多数内置类(Date、RegExp、Map、Set、ArrayBuffer 等)自动保留原型链,且天然支持循环引用:
- 无需手动处理 constructor 或 prototype 赋值逻辑
- 拷贝后的 Date 实例仍是
Date类型,instanceof Date为true - 不支持函数、undefined、Symbol 和 WeakMap/WeakSet —— 这是规范限制,不是 bug
- 若需兼容旧环境,可用
ungap/structured-clone垫片,但注意其 polyfill 不模拟原型链保留(仅还原数据结构)
自定义深拷贝需显式重建原型关系
当必须手写或兼容老环境时,不能只复制属性,要主动恢复原型链:
- 检测原对象构造器:
obj.constructor,若存在且非Object,用Object.create(obj.constructor.prototype)创建新实例 - 对普通对象(
constructor === Object),可跳过原型重建,但需注意不可枚举属性是否需保留 - 避免直接赋值
copy.__proto__ = obj.__proto__—— 在严格模式或某些引擎中可能失败,且不兼容冻结对象 - 若目标类有静态属性或 Symbol 属性,需额外遍历
Object.getOwnPropertyDescriptors(obj.constructor)并设置到新构造器上
绕过原型链依赖的设计策略
在核心业务逻辑中减少对 instanceof 或原型方法的强依赖,可降低拷贝风险:
- 用鸭子类型代替类型判断:检查
obj.getDate是否为函数,而非obj instanceof Date - 将关键行为封装为纯函数,接收原始数据而非实例(如
formatDate(dateObj)→formatDate(timestamp)) - 对自定义类,提供
toJSON()和静态fromJSON()方法,让序列化/反序列化可控可扩展 - 避免在原型上挂载状态或闭包,防止拷贝后状态错乱
验证原型链是否真正保留
上线前务必加入断言校验,不能只测数据字段:
expect(copy instanceof OriginalClass).toBe(true)expect(typeof copy.prototypeMethod).toBe('function')expect(Object.getPrototypeOf(copy) === OriginalClass.prototype).toBe(true)- 对继承链多层的类,检查
copy.__proto__.__proto__是否匹配预期










