Object.assign只进行浅拷贝,不处理嵌套对象合并、Symbol键、不可枚举属性及原型链,且IE不支持;应优先用解构或structuredClone+递归合并。

Object.assign 不能深拷贝嵌套对象
它只做一层浅拷贝,遇到 target 和 source 中的属性值是引用类型(如 Object、Array)时,只会复制引用地址,不会递归处理。修改合并后对象里的嵌套属性,会意外影响原对象。
- 比如
Object.assign({ a: { b: 1 } }, { a: { c: 2 } })得到的是{ a: { c: 2 } }——a被完全覆盖,不是合并{ b: 1, c: 2 } - 如果想“合并嵌套”,得自己写逻辑或用
structuredClone+ 递归合并,或者改用lodash.merge - 注意:
Object.assign对null或undefined源对象会跳过,但对原始值(如42、"str")会自动包装成对象再读取自有属性(通常结果为空)
Object.assign 无法处理不可枚举或 Symbol 属性
它只拷贝源对象上可枚举的自有字符串键属性,Symbol 类型的键和 Object.defineProperty 设置的 enumerable: false 属性都会被忽略。
const sym = Symbol('key'); const obj = { a: 1 }; Object.defineProperty(obj, 'b', { value: 2, enumerable: false }); obj[sym] = 3;-
Object.assign({}, obj)结果只有{ a: 1 },b和sym都丢了 - 若需完整拷贝,考虑
Reflect.ownKeys+ 手动遍历,或用structuredClone(仅限可序列化值)
Object.assign 的参数顺序错误会导致静默覆盖
第一个参数是目标对象(target),后续都是源对象(sources)。如果误把空对象写在后面,比如 Object.assign(a, b, {}),最后一个空对象会覆盖前面所有内容,导致 a 变成空对象 —— 这类 bug 不报错,但数据全丢。
- 常见误写:
Object.assign({}, obj1, obj2)是安全的(目标是新对象);但Object.assign(obj1, obj2, {})就危险 - 多个源对象同名属性按顺序覆盖:
Object.assign({}, {a:1}, {a:2}, {a:3})→{a:3} - 避免直接修改原对象,除非你明确需要副作用;否则始终把空对象
{}当作第一个参数
Object.assign 在 IE 中不支持,且无原型链继承能力
IE 全系(包括 IE11)都不支持 Object.assign,必须用 polyfill 或转译。另外,它不会拷贝原型上的属性,也不会设置新对象的 __proto__,返回的对象原型永远是 Object.prototype。
立即学习“Java免费学习笔记(深入)”;
- 如果你依赖某个构造函数的原型方法(比如
myDate.format()),用Object.assign合并后得到的是普通Object,不再有那些方法 - 需要保持实例类型?只能手动赋值或用
Object.setPrototypeOf(注意性能与兼容性) - 现代项目建议用解构赋值替代简单场景:
{ ...obj1, ...obj2 },但注意它也有同样浅拷贝和不可枚举限制
const target = { x: 1, y: { z: 2 } };
const source = { y: { w: 3 }, n: 4 };
const result = Object.assign(target, source);
// result === target → true
// result 是 { x: 1, y: { w: 3 }, n: 4 }
// 注意:target.y 原来的 { z: 2 } 已被整个替换,不是合并
真正麻烦的从来不是“怎么合并”,而是“哪些东西你以为合并了,其实没合进去”——比如嵌套对象被覆盖、Symbol 键消失、原型方法丢失,这些都不会报错,只在运行时悄悄出问题。











