Object.assign()按源对象从左到右顺序浅拷贝自有可枚举属性,后出现的同名属性覆盖先出现的,忽略null/undefined,原始值仅字符串有索引属性可拷贝。

Object.assign() 合并对象时,属性按源对象(source)的顺序从左到右依次拷贝,后出现的同名属性会覆盖先出现的——这是它的核心覆盖规则。它只做**浅拷贝**,不递归处理嵌套对象,也不会跳过 undefined 或 null 源对象(但会跳过原始值如字符串、数字等,仅处理可枚举自有属性)。
覆盖顺序:从左到右,后写入者胜出
Object.assign(target, ...sources) 中,target 是目标对象,sources 是一个或多个源对象。属性按 sources 的排列顺序逐个复制:
- 第一个 source 的属性先写入 target;
- 第二个 source 中与 target(或前一个 source)同名的属性会直接覆盖;
- 后续 source 依此类推,靠后的源对象拥有更高优先级。
例如:
const a = { x: 1, y: 2 };const b = { y: 3, z: 4 };
const c = { x: 5, z: 6 };
const res = Object.assign({}, a, b, c); // { x: 5, y: 3, z: 6 }
只覆盖“自有且可枚举”属性,不处理原型链
Object.assign 只遍历每个源对象自身的、可枚举(enumerable: true)属性。继承来的属性、不可枚举属性(如 Object.defineProperty 设置的 enumerable: false)均被忽略。
立即学习“Java免费学习笔记(深入)”;
- 即使 target 原型上有同名属性,也不会被覆盖或影响;
- 源对象若通过 Object.create(null) 创建(无原型),仍可正常拷贝其自有属性;
- Symbol 类型的可枚举属性也会被复制(ES2015+ 支持)。
浅拷贝:嵌套对象引用照搬,不深合并
Object.assign 不会递归处理对象内部的嵌套结构。如果多个 source 都有同名对象属性,后者会整个替换前者,而不是合并其子属性。
- 比如 target.a = { p: 1 },source1.a = { q: 2 },source2.a = { r: 3 },最终 target.a 是 { r: 3 },不是 { p: 1, q: 2, r: 3 };
- 若需深合并,必须借助第三方库(如 lodash.merge)或手写递归逻辑;
- 数组也被视为普通对象,同样按引用覆盖,不会 concat 或 merge 元素。
null / undefined 源对象被跳过,原始值报错
Object.assign 会忽略值为 null 或 undefined 的源对象(不报错,也不执行任何操作),但遇到字符串、数字、布尔值等原始值时,会尝试将其转为包装对象再遍历——此时只有字符串的索引属性(如 "abc" → {0:'a', 1:'b', 2:'c'})会被拷贝,其他原始值通常无有效可枚举属性,结果为空操作。
- Object.assign({}, {a:1}, null, {b:2}) → {a:1, b:2};
- Object.assign({}, 'ab') → {0:'a', 1:'b'};
- Object.assign({}, 42) → {}(Number.prototype 上无自有可枚举属性)。










