如何区分继承属性拷贝限制?为何Object.assign无法复制原型链上的原始方法?
- 内容介绍
- 相关推荐
本文共计657个文字,预计阅读时间需要3分钟。
`Object.assign()` 不复制原型链上的属性,因为它仅遍历并复制对象自身的自有属性(即拥有 `own`、`enumerable` 属性的属性)。继承自原型的属性不属于自身属性,因此不会被复制。
它只读取对象自身的属性描述符
JavaScript 中每个对象都有一个内部属性 [[Prototype]],指向其原型。原型上的方法或属性是通过属性查找机制“访问到”的,但并非存在于该对象实例上。Object.assign 的实现逻辑等价于:
- 调用
Object.keys(source)获取所有可枚举的自有属性名(不包括原型链上的) - 对每个键,执行
target[key] = source[key] - 而
Object.keys()明确不包含继承属性、不可枚举属性、symbol 键(除非显式处理)
看个直观例子
下面创建一个带原型方法的对象:
const parent = { sayHi() { return 'Hello'; } };const child = Object.create(parent);
child.name = 'Alice';
console.log(child.name); // 'Alice' → 自身属性,可枚举
console.log(child.sayHi()); // 'Hello' → 继承方法,但 child 本身没有 sayHi 键
console.log('sayHi' in child); // true(存在)
console.log(child.hasOwnProperty('sayHi')); // false(非自有)
const copy = Object.assign({}, child);
console.log(copy); // { name: 'Alice' } —— sayHi 消失了
这不是 bug,而是设计意图
Object.assign 的定位是“对象属性合并/克隆”,不是“完整对象结构重建”。它的行为与以下操作一致:
-
for...in循环会遍历继承属性,但 Object.assign 不会 -
Object.getOwnPropertyNames()能拿到不可枚举自有属性,但 Object.assign 也不处理它们 - 它专注的是“可被 JSON 序列化”那一类常规数据属性,而非运行时行为载体(如原型方法)
如果真需要拷贝原型行为,得换思路
原型方法本质是共享逻辑,通常不该“拷贝”,而应保持继承关系。若确实要让副本拥有相同能力,有几种合理做法:
- 让副本也继承同一原型:
Object.setPrototypeOf(copy, Object.getPrototypeOf(child)) - 手动提取并赋值:
copy.sayHi = child.sayHi(仅适用于已知方法名) - 使用
Object.getOwnPropertyDescriptors(child)+Object.defineProperties(),但这仍不处理原型,只强化自有属性控制
本文共计657个文字,预计阅读时间需要3分钟。
`Object.assign()` 不复制原型链上的属性,因为它仅遍历并复制对象自身的自有属性(即拥有 `own`、`enumerable` 属性的属性)。继承自原型的属性不属于自身属性,因此不会被复制。
它只读取对象自身的属性描述符
JavaScript 中每个对象都有一个内部属性 [[Prototype]],指向其原型。原型上的方法或属性是通过属性查找机制“访问到”的,但并非存在于该对象实例上。Object.assign 的实现逻辑等价于:
- 调用
Object.keys(source)获取所有可枚举的自有属性名(不包括原型链上的) - 对每个键,执行
target[key] = source[key] - 而
Object.keys()明确不包含继承属性、不可枚举属性、symbol 键(除非显式处理)
看个直观例子
下面创建一个带原型方法的对象:
const parent = { sayHi() { return 'Hello'; } };const child = Object.create(parent);
child.name = 'Alice';
console.log(child.name); // 'Alice' → 自身属性,可枚举
console.log(child.sayHi()); // 'Hello' → 继承方法,但 child 本身没有 sayHi 键
console.log('sayHi' in child); // true(存在)
console.log(child.hasOwnProperty('sayHi')); // false(非自有)
const copy = Object.assign({}, child);
console.log(copy); // { name: 'Alice' } —— sayHi 消失了
这不是 bug,而是设计意图
Object.assign 的定位是“对象属性合并/克隆”,不是“完整对象结构重建”。它的行为与以下操作一致:
-
for...in循环会遍历继承属性,但 Object.assign 不会 -
Object.getOwnPropertyNames()能拿到不可枚举自有属性,但 Object.assign 也不处理它们 - 它专注的是“可被 JSON 序列化”那一类常规数据属性,而非运行时行为载体(如原型方法)
如果真需要拷贝原型行为,得换思路
原型方法本质是共享逻辑,通常不该“拷贝”,而应保持继承关系。若确实要让副本拥有相同能力,有几种合理做法:
- 让副本也继承同一原型:
Object.setPrototypeOf(copy, Object.getPrototypeOf(child)) - 手动提取并赋值:
copy.sayHi = child.sayHi(仅适用于已知方法名) - 使用
Object.getOwnPropertyDescriptors(child)+Object.defineProperties(),但这仍不处理原型,只强化自有属性控制

