使用Object.assign合并对象时,如何实现数组值的合并而非覆盖?
如何合并对象中相同键的数组元素而非替换?
嘿,这个问题我之前也踩过坑!Object.assign()(包括扩展运算符{...obj1, ...obj2})做的是浅层次的属性覆盖——当遇到数组这种引用类型的属性时,它只会直接用新对象的属性值替换旧对象的,不会帮你合并数组里的元素,这就是为啥你的4123数组最后只剩Peter那一项的原因。
要实现你想要的“相同键下数组合并,其他键正常保留/添加”的效果,我们需要写一个自定义的合并函数来控制逻辑。
方案一:自定义遍历合并函数
先定义你的原始对象:
const json1 = { '4123': [ { name: 'John', age: '29' } ], '1514': [ { name: 'Kelly', age: '25' } ] }; const json2 = { '4123': [ { name: 'Peter', age: '53' } ], '567': [ { name: 'Joost', age: '61' } ] };
然后写合并函数,核心逻辑是:遍历所有键,判断如果两个对象都有该键且都是数组,就合并数组;否则直接保留/添加属性:
function mergeWithArrayConcat(obj1, obj2) { // 创建新对象,避免修改原始对象 const merged = { ...obj1 }; for (const key in obj2) { if (obj2.hasOwnProperty(key)) { const existingValue = merged[key]; const newValue = obj2[key]; // 当两边都是数组时,合并元素 if (Array.isArray(existingValue) && Array.isArray(newValue)) { merged[key] = [...existingValue, ...newValue]; } else { // 非数组情况直接赋值(新键添加,旧键覆盖) merged[key] = newValue; } } } return merged; }
调用函数得到结果:
const finalResult = mergeWithArrayConcat(json1, json2); console.log(finalResult);
输出完全符合你的需求:
{ '4123': [ { name: 'John', age: '29' }, { name: 'Peter', age: '53' } ], '1514': [ { name: 'Kelly', age: '25' } ], '567': [ { name: 'Joost', age: '61' } ] }
方案二:用reduce简化实现
如果你喜欢更简洁的写法,可以用Object.keys和reduce来实现相同逻辑:
const mergedResult = Object.keys({ ...json1, ...json2 }).reduce((acc, key) => { const valFrom1 = json1[key]; const valFrom2 = json2[key]; if (valFrom1 && valFrom2 && Array.isArray(valFrom1) && Array.isArray(valFrom2)) { acc[key] = [...valFrom1, ...valFrom2]; } else { // 优先取json2的值,没有则取json1的 acc[key] = valFrom2 ?? valFrom1; } return acc; }, {});
这个写法更偏向函数式风格,逻辑和方案一完全一致,只是表达方式不同。
为什么Object.assign不行?
再补充下原理:Object.assign()在处理属性时,会直接将源对象的属性值赋值给目标对象。如果属性值是引用类型(比如数组、对象),它只会复制引用,而不会深拷贝或者合并内容。所以当你用Object.assign(json1, json2)时,json2的4123数组会直接替换掉json1里的同键数组,而不是合并元素。
内容的提问来源于stack exchange,提问作者Kid Diamond
相关产品推荐
相关产品推荐

