js Object.assign合并对象

2026-05-13 23:00:34 1629阅读 0评论

别再误用 Object.assign 了,合并对象前的这几点坑得先避

做前端开发久了,处理配置项或者用户信息合并是家常便饭。以前大家习惯用 Object.assign() 来搞定,代码写起来确实顺手。但最近 review 代码时,发现不少同事还在“无脑”套用它,结果埋下了不少隐患。今天咱们就抛开枯燥的文档定义,聊聊在实际项目中,怎么用这个 API 才不踩雷。

它是“原地修改”,而不是“生成新值”

很多人第一次接触 Object.assign(target, ...sources) 时,默认它像数学加法一样返回一个新结果。实际上,它直接修改并返回第一个参数(target)

const defaults = { theme: 'light', lang: 'zh' };
const userOpts = { theme: 'dark' };

// ❌ 常见误区:认为 defaults 还是原样
const finalConfig = Object.assign(defaults, userOpts); 

console.log(defaults.theme); // dark!defaults 被污染了
console.log(finalConfig === defaults); // true

如果你在意数据不可变性,比如在使用 Redux 或 Vue 响应式状态时,这种写法会导致副作用。正确的做法是传入一个空对象作为第一个参数。虽然这样会创建新内存,但在维护性和调试上能避免很多玄学问题。

const finalConfig = Object.assign({}, defaults, userOpts);

浅拷贝带来的嵌套陷阱

这是最容易被忽视的逻辑漏洞。Object.assign 只进行一层浅拷贝。当你的源对象里包含嵌套对象时,修改合并后的深层属性,会反过来影响原始数据。

const base = { style: { color: 'red', size: 12 } };
const update = { style: { color: 'blue' } };

const merged = Object.assign({}, base, update);
merged.style.size = 20; 
// ⚠️ base.style.size 也会变成 20,如果底层还依赖 base 的话

这种情况下,简单的合并已经不够用了。如果必须处理深层结构,要么手写递归深度合并逻辑,要么引入成熟的 lodash 库,不要试图用多次嵌套的 Object.assign 去硬解,那样可读性简直灾难。

一些你可能不知道的“过滤机制”

除了深浅拷贝,Object.assign 还有个隐形规则:它只会复制可枚举的自有属性。这意味着原型链上的属性、不可枚举属性(enumerable: false)都会被忽略。

更有趣的是,如果遇到访问器属性(getter/setter),它会执行 setter 方法并将值赋值给目标对象,而不是直接把 getter/setter 描述符复制过去。

const source = {
  get name() { return 'Guest'; }
};

const target = {};
Object.assign(target, source);
// target.name 不再是访问器,而是一个普通字符串 'Guest'
console.log(Object.getOwnPropertyDescriptor(target, 'name').get); // undefined

如果你的业务逻辑依赖对象的访问器特性,直接用 Object.defineProperty 或者展开运算符可能比 Object.assign 更可控。

什么时候选展开运算符 ...

现在大部分新项目都倾向于用扩展运算符 { ...obj } 来做合并。它的行为与 Object.assign 基本一致,也是浅拷贝且不会改变原对象(除非你手动赋值回去)。

两者的核心差异在于意图表达和语法糖:

  1. 可读性{ ...a, ...b } 更符合现代 ES6+ 风格,阅读成本更低,一眼就能看出是在构建新对象。
  2. 安全性Object.assign(null, obj) 会报错,而 { ...null } 是合法的(结果为空对象),这在某些防御性编程中反而更安全。
  3. 性能:在简单合并场景下,两者性能差异微乎其微,不用过度纠结。

但别忘了,原生方法的兼容性更好。如果项目要支持 IE11 以下环境,Object.assign 配合 Polyfill 依然是稳妥的选择。

写在最后

工具没有绝对的好坏,只有适不适合场景。Object.assign 依然强大,特别是在需要显式 mutate 某个目标对象以提升性能的特定库开发中。但对于日常的业务开发,优先保证数据流清晰和无副作用

下次准备合并对象前,不妨花两秒确认一下:你是想修改原对象,还是生成新配置?有没有深层嵌套的结构?确认好这两点,再决定是用 assign 还是展开符,代码的健壮性自然就上去了。

文章版权声明:除非注明,否则均为Dark零点博客原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
验证码
评论列表 (暂无评论,1629人围观)

还没有评论,来说两句吧...

目录[+]