深拷贝需保留原型链,应使用object.create()配合object.getprototypeof()创建新对象骨架,再递归复制自有属性(含symbol和不可枚举属性),并针对date、regexp、array等内置类型单独处理。

深拷贝时保留原型链,关键不是“复制原型”,而是让新对象的 __proto__ 正确指向原对象的原型,同时确保构造器、方法和不可枚举属性不丢失。JSON 方案(JSON.parse(JSON.stringify()))完全失效,因为它只处理可枚举自有属性,函数、Symbol、原型、getter/setter 全部丢弃。
用 Object.create() + 构造器重建实例
这是最可靠的方式:先获取原对象的原型,再用它创建新对象骨架,最后填充自有属性。
- 通过
Object.getPrototypeOf(obj)获取原对象原型 - 调用
Object.create(proto)创建一个空对象,其__proto__已正确指向原原型 - 再递归深拷贝所有自有属性(包括 Symbol 和不可枚举属性),赋值到该新对象上
- 若对象有明确构造器(如
obj.constructor === MyClass),且该构造器支持无参实例化,也可用new obj.constructor(),但需注意构造逻辑副作用
避免直接操作 __proto__
__proto__ 是非标准属性,部分环境(如严格模式、某些旧引擎)不支持直接赋值。应使用标准 API:
- 推荐:
Object.setPrototypeOf(newObj, originalProto) - 不推荐:
newObj.__proto__ = originalProto(兼容性差、性能不佳、ES 规范不鼓励) - 更稳妥:始终优先走
Object.create(originalProto)路径,天然规避设置问题
内置类型要单独处理
Date、RegExp、Array、Map、Set 等都有自己的原型链和构造逻辑,不能统一用 Object.create()。必须按类型分别重建:
-
obj instanceof Date→new Date(obj.getTime()) -
obj instanceof RegExp→new RegExp(obj.source, obj.flags) -
Array.isArray(obj)→obj.map(item => deepClone(item)),而非[]+Object.create(Array.prototype)(会丢失数组方法) - Map / Set 需遍历 entries 或 values,用对应构造器新建实例
保留 Symbol 属性和不可枚举属性
原型链完整 ≠ 功能完整。若原对象有 Symbol 键或 Object.defineProperty 定义的不可枚举属性,它们也属于“原型行为”的一部分(比如私有状态或内部标识),需显式复制:
- 用
Object.getOwnPropertySymbols(obj)获取所有 Symbol 键 - 用
Object.getOwnPropertyDescriptors(obj)获取包括enumerable: false、writable、configurable在内的完整描述符 - 对每个 descriptor,调用
Object.defineProperty(newObj, key, descriptor)











