浅拷贝默认不保留原型链属性,因只复制自身可枚举属性;要保持原型继承,需使新对象原型指向原对象原型,如用Object.create(Object.getPrototypeOf(obj))配合Object.assign。

浅拷贝本身不会保留原型链上的属性,因为浅拷贝只复制对象自身的可枚举属性(即 Object.keys() 能拿到的那些),而原型链上的属性是继承来的、不可枚举(除非显式设置为可枚举),所以默认不会被拷贝。要让拷贝后的对象仍能访问原型链上的属性,关键不是“拷贝原型”,而是**确保新对象的原型指向原对象的原型**。
保持原型链的核心:设置正确的 __proto__ 或使用 Object.setPrototypeOf()
JavaScript 中对象的行为(包括属性访问)依赖于其内部的 [[Prototype]] 链。只要新对象的原型和原对象一致,就能继续继承原型上的方法和属性。
- 用
Object.create(Object.getPrototypeOf(obj))创建新对象,再逐个赋值自身属性 - 拷贝后手动调用
Object.setPrototypeOf(newObj, Object.getPrototypeOf(original)) - 避免直接用
{...obj}或Object.assign({}, obj)—— 它们创建的对象原型默认是Object.prototype,丢失了自定义原型
常见浅拷贝方式对比(是否保原型)
❌ 不保原型的方式:{...obj}、Object.assign({}, obj)、structuredClone()(仅限可序列化属性,且重置原型为 Object.prototype)—— 这些都生成一个“干净”的普通对象,原型链被切断。
✅ 保原型的方式:Object.assign(Object.create(Object.getPrototypeOf(obj)), obj)
或更清晰地分两步:
const copy = Object.create(Object.getPrototypeOf(obj));Object.assign(copy, obj);
这样 copy 的原型就是原对象的原型,所有继承的方法(如 obj.customMethod())在 copy 上依然可用。
注意 constructor 和其他不可枚举自有属性
原型链继承的是“读取时查找”的属性,但 constructor 通常是原型上的属性,也会被继承;不过如果原对象有自定义的不可枚举自有属性(比如用 Object.defineProperty 添加的),浅拷贝默认不复制它们——除非你显式遍历 Object.getOwnPropertyNames() 并处理 getOwnPropertyDescriptor。
- 若需完整保留不可枚举自有属性,浅拷贝就不够用了,得考虑深拷贝策略或手动复制描述符
- 但绝大多数场景下,只关心可枚举属性 + 原型继承,上面的
Object.create + Object.assign组合已足够
ES6 类实例的浅拷贝示例
假设有一个类:
class Person {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, ${this.name}`;
}
}
实例 const p = new Person('Alice'); 的原型是 Person.prototype。
正确浅拷贝并保持 greet() 可用:
const p2 = Object.assign(Object.create(Object.getPrototypeOf(p)), p);p2.greet(); // ✅ 'Hello, Alice'p2 instanceof Person; // ✅ true
而 {...p} 得到的对象 instanceof Person 为 false,且无法调用 greet()(除非方法被定义在实例上)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











