为何JavaScript对象合并会覆盖重复属性,数组扩展仅做元素拼接?
为什么JavaScript扩展运算符在合并对象和数组时行为不同?
这本质是由对象和数组的核心特性差异决定的:
对象的属性唯一性导致覆盖
对象的核心是「键值对集合」,同一个对象中不允许存在重复的属性名——这是JavaScript对象的基础规则。
当用扩展运算符合并对象时,逻辑是按顺序将后续对象的属性依次“写入”新对象:如果遇到和前面重复的属性名,后面的属性值会直接覆盖前面的,这和你直接给对象赋值obj.b = 4会覆盖原有obj.b的逻辑完全一致。
比如你给出的例子:
const a = {'a': 1, 'b': 2} const b = {'b': 4, 'c': 3} console.log({...a, ...b})
新对象先复制a的所有属性,再复制b的属性,当遇到重复的b时,b的4就覆盖了a里的2,最终得到{a:1, b:4, c:3}。
数组的元素有序性导致拼接
数组的核心是「有序元素列表」,它允许存在重复元素,元素的标识是索引而非值本身。
扩展运算符处理数组时,只是简单地把每个数组的元素依次展开,然后按顺序拼接成新数组——它不会检查元素值是否重复,因为重复元素在数组里是完全合法的。
比如你的数组例子:
const c = [1,2] const d = [2,3] console.log([...c, ...d])
先展开c得到1,2,再展开d得到2,3,把这些元素按顺序拼起来,就得到[1,2,2,3],完全保留了两个数组里的所有元素。
设计逻辑的合理性
这种差异是符合开发者直觉的:
- 对象合并时,我们通常希望后续的配置能覆盖前面的(比如用默认配置+自定义配置的场景),所以“后面覆盖前面”是合理的规则;
- 数组拼接时,我们大多只是想把两个列表的元素合在一起,而不是自动去重或覆盖,所以直接保留所有元素是更通用的设计。
内容的提问来源于stack exchange,提问作者Rohan Bisht
相关产品推荐
相关产品推荐

