深拷贝默认不处理原型链上的继承属性,因为其目标是创建独立新对象,而继承属性属于共享原型而非实例自有状态;structuredClone仅对Date等内置类保留原型,对自定义类仍返回plain Object。

JS 深拷贝默认不处理原型链上的继承属性——因为“克隆”目标是创建一个**独立的新对象**,而继承属性属于原型,不是对象自身的状态。所以标准深拷贝(如 structuredClone、JSON.parse(JSON.stringify())、Lodash 的 cloneDeep)都只拷贝**自有可枚举属性**,完全忽略原型链。
为什么原型链属性通常不被拷贝
原型链上的属性是共享的,不是实例私有数据。深拷贝的核心诉求是“隔离变更”,如果把原型属性也复制成自有属性,会破坏封装性、掩盖继承关系,还可能导致后续 instanceof 判断失效或方法行为异常。
例如:
const Parent = function() {}; Parent.prototype.say = () => 'hello';const child = new Parent();
// child.say 是继承来的,不是 child 自身属性
console.log(child.hasOwnProperty('say')); // false
若明确需要保留原型链结构
这不是“拷贝原型属性”,而是“让新对象继承原对象的原型”。关键在于:用 Object.create() 创建新对象,并显式指定其原型,再递归填充自有属性。
- 用
Object.getPrototypeOf(obj)获取原对象的原型 - 用
Object.create(proto)创建空对象,其__proto__指向该原型 - 用
Object.getOwnPropertyDescriptors(obj)获取所有自有属性描述符(含 getter/setter、writable、configurable 等) - 对每个属性值做深拷贝(递归处理对象/数组,特殊类型如 Date、Map 单独构造),再用
Object.defineProperties(newObj, descriptors)定义到新对象上 - 用
WeakMap缓存已处理的对象,防止循环引用无限递归
structuredClone 能否保留原型链
不能通用保留。它对部分内置类(如 Date、RegExp、Error)能维持其构造器和原型,但对普通自定义对象(如 new MyClass()),结果总是 Object 实例,原型链丢失。
也就是说:structuredClone(new Date()) 返回仍是 Date 实例;但 structuredClone(new MyClass()) 返回的是 plain object,不再 instanceof MyClass。
实际开发中怎么选
绝大多数场景下,你不需要也不应该“克隆原型链”:
- 状态数据(API 响应、表单、配置)用
structuredClone或 JSON 方案即可,它们本就不该依赖原型方法 - 需要保持类实例语义时,优先用构造函数重建:
new MyClass(...Object.values(deepCopy(original))) - 仅当明确设计为“原型继承 + 数据快照”模式(极少见),才手写带
Object.create的深拷贝逻辑
原型链是行为复用机制,不是数据载体。深拷贝管数据,原型管行为——分清这两者,就抓住了本质。











