Object.assign仅复制对象自身可枚举属性,不处理原型链;若需合并原型属性,须手动遍历原型链并逐层提取自有属性后合并。

Object.assign 本身不处理原型链,它只遍历并复制对象自身的可枚举属性(即 Object.keys() 返回的属性),完全忽略原型上的属性。因此,它无法直接实现“对多级原型属性的浅拷贝合并”——这个前提本身就存在概念混淆。
Object.assign 的实际行为:仅操作自身属性
它接收一个目标对象和若干源对象,把所有源对象的自身可枚举属性依次复制到目标对象上。原型链上的属性不会被读取、更不会被“合并”或“拷贝”。
例如:
const parent = { a: 1, b: 2 };
const child = Object.create(parent);
child.c = 3;
const target = {};
Object.assign(target, child); // 只复制 c: 3
console.log(target); // { c: 3 }
console.log(target.a); // undefined(a 在原型上,未被复制)
若想“合并原型链上的属性”,需手动提取
必须显式遍历整个原型链,逐层获取自身属性,再合并。可用 Object.getPrototypeOf() 和 Object.getOwnPropertyNames() 配合实现,但要注意:
- 属性名重复时,靠近实例的值会覆盖原型上的同名值(符合常规继承逻辑)
- 不可枚举属性(如
constructor)默认不被包含,需额外判断propertyIsEnumerable - 访问器属性(getter/setter)会被转为数据属性(值是 getter 执行结果),可能丢失行为语义
常见逻辑陷阱与风险
开发者误以为 Object.assign 能“深挖原型”时,容易掉入以下坑:
- 静默丢失继承关系:合并后得到纯扁平对象,原型链断裂,原方法、计算属性全部失效
- 引用未解耦:浅拷贝下,嵌套对象/数组仍共享引用,修改 target 中的 nested.x 会影响源对象
- Symbol 属性被忽略:Object.assign 不复制 Symbol 键属性(除非显式传入)
-
构造器信息丢失:合并结果总是普通
Object实例,无法保留原始 constructor 或 instanceof 判断
替代思路:按需选择更合适的工具
根据真实需求选择方案:
- 仅需“扁平化实例状态” → 用
{...obj}或Object.assign({}, obj)即可,无需碰原型 - 需完整克隆含原型结构的对象 → 应使用
Object.setPrototypeOf(clone, Object.getPrototypeOf(obj))手动重建链 - 需合并多个对象(含继承)的状态 → 先用
__proto__或Object.getPrototypeOf收集所有层级的自有属性,再用 Object.assign 合并到空对象 - 涉及深层嵌套或复杂类型 → 直接换用
structuredClone(现代环境)或成熟库如 lodash 的cloneDeep/merge

















