Object.assign 不复制原型属性,只拷贝对象自身的可枚举属性;因其内部仅遍历 Object.keys() 返回的键,忽略继承属性;如需合并原型属性需手动实现或显式提取,或改用 Object.create + Object.assign 模拟继承。

Object.assign 不会复制原型上的属性,它只遍历并拷贝对象自身的可枚举属性(即 `Object.keys()` 返回的那些),原型链上的属性会被忽略。
为什么 Object.assign 无法合并原型属性
这是由 `Object.assign` 的设计决定的:它内部使用 `for...in` 循环的等效逻辑(但仅限自身属性),实际行为类似:
- 获取源对象的所有自身可枚举属性键(不包括继承来的)
- 逐个读取这些键对应的值,并赋给目标对象
- 原型上的属性(如通过 `prototype` 添加的方法或数据)不在遍历范围内
想合并原型属性?得手动处理
如果确实需要把原型链上的可枚举属性也合并进来,可以自己实现一个扩展版本。例如:
function assignWithPrototype(target, ...sources) {
sources.forEach(source => {
// 先拷贝自身属性
Object.assign(target, source);
// 再沿原型链向上,拷贝每个原型的自身可枚举属性
let proto = Object.getPrototypeOf(source);
while (proto !== null) {
Object.assign(target, proto);
proto = Object.getPrototypeOf(proto);
}
});
return target;
}
注意:这样会把所有原型上的可枚举属性(包括 `toString`、`hasOwnProperty` 等原生方法)也都拷过去,容易污染目标对象,实际中需谨慎过滤。
立即学习“Java免费学习笔记(深入)”;
更安全的做法:明确指定要合并的原型属性
与其盲目合并整个原型链,不如显式提取你需要的属性:
- 用 `Object.getOwnPropertyNames(Obj.prototype)` 获取原型上所有自有属性名(含不可枚举的)
- 结合 `Object.prototype.propertyIsEnumerable.call(Obj.prototype, key)` 判断是否可枚举
- 或者直接写死要拷的属性名,比如:
target.method = source.constructor.prototype.method
替代思路:用 Object.create + Object.assign 模拟继承效果
如果你的目标是“让目标对象拥有源对象原型的行为”,通常更好的方式是构造新对象并设置原型:
const merged = Object.assign(Object.create(source.prototype), ownProps)- 或用类/构造函数组合,比强行扁平化原型更符合 JavaScript 原型设计本意


















