JavaScript中如何合并对象数组为单个对象,包含嵌套对象?
深度合并对象数组为通用嵌套对象
你遇到的问题是Object.assign只能做浅合并,没法处理嵌套对象的深度合并——它只会把后面对象的顶层属性直接覆盖前面的,遇到嵌套对象时不会递归合并内部属性,反而会直接替换掉整个嵌套对象(你之前写的结果里出现两个b是不对的,实际上对象中不能有重复键,Object.assign会用后面的b完全覆盖前面的b,最终得到{a:1, b:{c:'x',d:8}},丢失了前面的k:[])。
要实现所有层级的对象合并,我们需要写一个递归的深度合并函数,遍历每个属性,遇到嵌套对象就递归处理,遇到数组则根据需求保留或合并(你的示例里是保留数组,所以我们先按这个逻辑实现)。
第一步:定义深度合并函数
// 判断是否是纯对象(排除数组和基本类型) function isObject(item) { return item && typeof item === 'object' && !Array.isArray(item); } // 递归深度合并多个对象 function deepMerge(target, ...sources) { // 如果没有源对象需要合并,直接返回目标对象 if (!sources.length) return target; const currentSource = sources.shift(); // 只有当目标和当前源都是纯对象时,才递归合并内部属性 if (isObject(target) && isObject(currentSource)) { for (const key in currentSource) { // 如果当前源的属性值是纯对象 if (isObject(currentSource[key])) { // 如果目标对象没有这个属性,先初始化一个空对象 if (!target[key]) Object.assign(target, { [key]: {} }); // 递归合并该属性的内部对象 deepMerge(target[key], currentSource[key]); } else if (Array.isArray(currentSource[key])) { // 如果是数组,直接保留源对象的数组(如果需要合并数组,可以改成 target[key] = [...(target[key] || []), ...currentSource[key]]) target[key] = currentSource[key]; } else { // 基本类型属性直接赋值(如果有重复的基本类型键,会用后面的值覆盖前面的) Object.assign(target, { [key]: currentSource[key] }); } } } // 递归处理剩下的源对象 return deepMerge(target, ...sources); }
第二步:使用函数合并你的数组
var list = [ { a: 1, b: { c: 'x', k: []} }, { a: 1, b: {c: 'x', d: 8} } ]; var mergedResult = deepMerge({}, ...list); console.log(mergedResult); // 输出结果:{ a: 1, b: { c: 'x', k: [], d: 8 } }
额外说明
- 如果你的场景中需要合并数组(比如两个对象的数组属性需要拼接),可以修改数组处理的代码,把直接赋值改成数组展开拼接:
target[key] = [...(target[key] || []), ...currentSource[key]]; - 如果遇到相同键的基本类型值不一致(比如一个对象
a:1,另一个a:2),这个函数会用最后一个对象的属性值覆盖前面的。如果需要保留所有不同的值,可以改成把值存入数组,比如:if (target[key] !== undefined && target[key] !== currentSource[key]) { target[key] = Array.isArray(target[key]) ? [...target[key], currentSource[key]] : [target[key], currentSource[key]]; } else { target[key] = currentSource[key]; }
内容的提问来源于stack exchange,提问作者mimic
相关产品推荐
相关产品推荐

