使用 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()
来保护原始数据。