17370845950

javascript如何合并对象_Object.assign方法有哪些使用限制?
Object.assign只进行浅拷贝,不处理嵌套对象合并、Symbol键、不可枚举属性及原型链,且IE不支持;应优先用解构或structuredClone+递归合并。

Object.assign 不能深拷贝嵌套对象

它只做一层浅拷贝,遇到 targetsource 中的属性值是引用类型(如 ObjectArray)时,只会复制引用地址,不会递归处理。修改合并后对象里的嵌套属性,会意外影响原对象。

  • 比如 Object.assign({ a: { b: 1 } }, { a: { c: 2 } }) 得到的是 { a: { c: 2 } } —— a 被完全覆盖,不是合并 { b: 1, c: 2 }
  • 如果想“合并嵌套”,得自己写逻辑或用 structuredClone + 递归合并,或者改用 lodash.merge
  • 注意:Object.assignnullundefined 源对象会跳过,但对原始值(如 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 }bsym 都丢了
  • 若需完整拷贝,考虑 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

  • 如果你依赖某个构造函数的原型方法(比如 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 键消失、原型方法丢失,这些都不会报错,只在运行时悄悄出问题。