如何实现线性数组对象与嵌套结构数组对象的合并?
嵌套数组与线性数组的合并实现
需求说明
- 若数组B中的对象在数组A(含所有嵌套的
items子数组)中存在,原地替换A中的对应对象:保留原对象的所有属性,用B对象的属性覆盖同名属性 - 若B中的对象在A中不存在,将其添加为A根数组中第一个元素的同级对象(即追加到根数组末尾)
示例数据
原嵌套数组A
let a = [ { "key": "parent-1", "type": "parent", "items": [ { "key": "parent-1-1", "type": "parent", "items": [ { "key": "child-1-1", "dataType": "text", "description": "foo", "someproperty": "stays" } ] }, { "key": "parent-1-2", "type": "parent", "items": [ { "key": "child-1-2", "dataType": "text" } ] } ] } ]
用于修改的线性数组B
let b = [ { "key": "child-1-1", "dataType": "text", "description": "bar" }, { "key": "child-2", "dataType": "text", "description": "Since this does not appear in A it should be inserted as a next sibling to first array element (parent-1)" } ]
现有方案的问题
当前使用的线性合并方法仅能处理平级数组,无法遍历A的多层嵌套items结构,导致深层对象无法匹配和替换:
const c = [ ...a.filter(i => !b.some(j => j.key===i.key)), ...b.map(i => ({...a.find(j => j.key===i.key) ?? {}, ...i})) ] console.log(c)
改进的嵌套合并方案
通过递归遍历处理多层嵌套结构,实现需求中的合并逻辑:
// 递归查找并更新嵌套结构中的目标对象 function updateNestedItem(items, updateObj) { for (let i = 0; i < items.length; i++) { const item = items[i]; // 匹配到目标key,合并属性 if (item.key === updateObj.key) { Object.assign(item, updateObj); return true; } // 存在子items数组,递归查找 if (item.items && Array.isArray(item.items)) { const found = updateNestedItem(item.items, updateObj); if (found) return true; } } return false; } // 合并数组A和B的主函数 function mergeArrays(a, b) { // 深拷贝原数组,避免修改原始数据 const merged = JSON.parse(JSON.stringify(a)); // 逐个处理B中的对象 for (const obj of b) { const isFound = updateNestedItem(merged, obj); // 未找到匹配对象,追加到根数组末尾 if (!isFound) { merged.push(obj); } } return merged; } // 执行合并并输出结果 const c = mergeArrays(a, b); console.log(JSON.stringify(c, null, 2));
代码说明
updateNestedItem:递归遍历所有层级的items数组,找到匹配key的对象后,用Object.assign合并属性(保留原属性,仅覆盖B中存在的同名属性)mergeArrays:先对原数组A进行深拷贝(防止修改原始数据),再逐个处理B中的对象,匹配到则更新,未匹配到则追加到根数组- 深拷贝使用
JSON.parse(JSON.stringify)适用于示例中的普通对象场景,若需处理函数、Symbol等特殊类型,可替换为其他深拷贝方法(如Lodash的_.cloneDeep)
预期合并结果
c = [ { "key": "parent-1", "type": "parent", "items": [ { "key": "parent-1-1", "type": "parent", "items": [ { "key": "child-1-1", "dataType": "text", "description": "bar", "someproperty": "stays" } ] }, { "key": "parent-1-2", "type": "parent", "items": [ { "key": "child-1-2", "dataType": "text" } ] } ] }, { "key": "child-2", "dataType": "text", "description": "Since this does not appear in A it goes as sibling to first el: parent-1" } ]
内容的提问来源于stack exchange,提问作者Scott B
相关产品推荐
相关产品推荐

