object.assign只拷贝自有且可枚举的属性,忽略原型链上所有属性(无论是否可枚举);判断依据是hasownproperty(key)与propertyisenumerable(key)同时为true。

Object.assign 不会拷贝原型属性,无论它是否可枚举——这是它最常被误解的一点。所谓“干扰”,其实是误以为“可枚举就能被拷贝”,而忽略了“必须同时满足‘自身属性’+‘可枚举’”这两个硬性条件。
原型属性根本不会进入 Object.assign 的处理范围
即使你手动把原型上的属性设为 enumerable: true,Object.assign 依然跳过它。因为它只遍历源对象自身的属性(即 obj.hasOwnProperty(key) === true 的那些),不查原型链。
例如:
const parent = { protoProp: '我可枚举' };
Object.defineProperty(parent, 'protoProp', { enumerable: true });
const child = Object.create(parent);
child.ownProp = '我自有';
const result = Object.assign({}, child);
console.log(result.ownProp); // '我自有' ✅
console.log(result.protoProp); // undefined ❌(哪怕 parent.protoProp.enumerable === true)
别被 for...in 或 Object.keys() 的表现带偏
for...in 会遍历可枚举的原型属性,Object.keys() 不会——但 Object.assign 和后者一致:只看自有 + 可枚举。所以:
- 如果一个属性能被
for...in看到,但Object.keys(obj)看不到 → 它是原型上的可枚举属性 → Object.assign 忽略它 - 如果
obj.propertyIsEnumerable('key') === false→ 说明它是不可枚举的自有属性 → Object.assign 同样忽略 - 只有
obj.hasOwnProperty('key') && obj.propertyIsEnumerable('key')同时为 true,才可能被拷贝
快速验证某属性是否会被 Object.assign 拷贝
写个小判断函数,比猜更可靠:
function isCopiedByAssign(obj, key) {
return obj.hasOwnProperty(key) && obj.propertyIsEnumerable(key);
}
const o = Object.create({ inherited: 1 });
o.own = 2;
Object.defineProperty(o, 'hidden', { value: 3, enumerable: false });
console.log(isCopiedByAssign(o, 'own')); // true → 会被拷贝
console.log(isCopiedByAssign(o, 'inherited')); // false → 原型属性,跳过
console.log(isCopiedByAssign(o, 'hidden')); // false → 不可枚举,跳过
真正影响拷贝结果的,是“自有性”优先于“可枚举性”
换句话说:先筛出所有自有属性,再在其中挑出可枚举的。原型属性连第一轮筛选都过不了。
- 可枚举性只在“自有属性池”里起过滤作用
- 原型链上的属性,不管
enumerable是 true 还是 false,全被挡在门外 - 想让某个原型行为参与拷贝?得先把它“提升”为自有属性(比如用
Object.assign(obj, Object.getPrototypeOf(obj)),但需谨慎)










