别再用 ... 扩展运算符了,这个新 API 合并对象更快更安全

demongao
4
2025-08-27

使用 JavaScript 扩展运算符(...)来合并对象,几乎成了每个开发者的肌肉记忆。

const defaults = { theme: 'dark', version: '1.0' };
const userConfig = { theme: 'light', showTips: true };

const finalConfig = { ...defaults, ...userConfig };
// { theme: 'light', version: '1.0', showTips: true }

一行代码,清晰地表达了意图,优雅地完成了合并。

但在某些场景下,它不仅可能带来性能瓶颈,甚至会埋下难以察觉的深坑。

扩展运算符 ... 与 Object.assign

我们先来回顾一下最常用的两种方法:扩展运算符和 Object.assign()

它们的共同点:都是浅拷贝

这是两者最大的共同点,也是它们最大的安全隐患。当对象的属性值是另一个对象或数组时,它们只拷贝引用,而不是创建一个全新的副本。

来看这个例子:

const source = {
 user: 'Alice',
 profile: {
    age: 25,
    hobbies: ['coding', 'reading']
  }
};

const merged = { ...source, user: 'Bob' };

// 现在,我们尝试修改 merged 对象中的嵌套数据
merged.profile.age = 30;

// 猜猜看原始的source对象会发生什么?
console.log(source.profile.age); // 输出: 30

问题大了! 我们只是想修改新对象 merged,却意外地“污染”了原始对象 source。在一个复杂的应用中,这种副作用极难追踪,引发各种诡异的 Bug。

Object.assign() 也存在完全相同的问题

structuredClone()

为了彻底解决浅拷贝带来的数据污染问题,Web 平台引入了一个强大的原生 API:structuredClone():使用结构化克隆算法,创建一个对象的深拷贝。

让我们用 structuredClone() 来重写上面的例子:

const source = {
 user: 'Alice',
 profile: {
    age: 25,
    hobbies: ['coding', 'reading']
  }
};

// 先深拷贝,再合并
const safeMerged = { ...structuredClone(source), user: 'Bob' };

// 再次尝试修改
safeMerged.profile.age = 30;

// 检查原始对象 source
console.log(source.profile.age); // 输出: 25 (🎉 安全!)

当需要处理包含嵌套对象或数组的复杂数据结构时,建议使用 structuredClone() 来保护原始数据。