JavaScript中基于ID深度合并嵌套对象的实现方案
基于ID的嵌套对象深度合并方案
针对嵌套数组需按指定ID匹配更新、避免重复的需求,以下是无需依赖lodash的自定义实现方案,核心逻辑是通过ID映射精准匹配并覆盖对象,同时保留未被更新的原有条目。
实现代码
// 按指定key合并两个数组:新对象覆盖同key旧对象,无重复条目 function mergeArraysById(oldArr, newArr, idKey = 'id') { const newItemMap = new Map(newArr.map(item => [item[idKey], item])); // 保留旧数组条目,用新数据覆盖匹配项;再加入旧数组没有的新条目 return [ ...oldArr.map(item => newItemMap.get(item[idKey]) || item), ...newArr.filter(item => !oldArr.some(oldItem => oldItem[idKey] === item[idKey])) ]; } // 深度合并对象:cards数组按iid合并,子数组按id合并 function deepMergeWithId(original, update) { // 非对象类型直接返回更新值(若存在) if (typeof original !== 'object' || original === null) { return update !== undefined ? update : original; } if (typeof update !== 'object' || update === null) { return update; } const merged = { ...original }; for (const key of Object.keys(update)) { const originalVal = merged[key]; const updateVal = update[key]; // 处理顶层cards数组,按iid匹配卡片 if (key === 'cards') { const updateCardMap = new Map(updateVal.map(card => [card.iid, card])); merged.cards = originalVal.map(originalCard => { const updateCard = updateCardMap.get(originalCard.iid); if (!updateCard) return originalCard; // 合并单个卡片内容 const mergedCard = { ...originalCard }; // 合并sub_arr子数组 if (updateCard.sub_arr) { mergedCard.sub_arr = mergeArraysById(originalCard.sub_arr || [], updateCard.sub_arr); } // 合并support子数组 if (updateCard.support) { mergedCard.support = mergeArraysById(originalCard.support || [], updateCard.support); } // 覆盖卡片的其他非数组属性 Object.keys(updateCard).forEach(cardKey => { if (!['sub_arr', 'support'].includes(cardKey)) { mergedCard[cardKey] = updateCard[cardKey]; } }); return mergedCard; }); // 添加更新数据中新增的卡片(若有) merged.cards.push(...updateVal.filter(updateCard => !originalVal.some(oc => oc.iid === updateCard.iid))); } else { // 其他属性递归深度合并 merged[key] = deepMergeWithId(originalVal, updateVal); } } return merged; } // 使用示例 const originalData = { "cards": [ { "iid": 154423, "number": 1, "name": "name", "sub_arr": [ { "name": "name", "id": "94184", "point": "6", "event": "cff" }, { "name": "name", "id": "90363", "event": "cff" }, { "name": "name", "id": "94185", "point": "3", "event": "cff" } ], "support": [ { "name": "Richardson", "id": "43478" }, { "name": "Jason", "id": "43582" } ] }, { "iid": 154430, "number": 2, "sub_arr": [ { "name": "name", "id": "94174", "point": "6", "event": "cff" }, { "name": "name", "id": "90373", "event": "cff" }, { "name": "name", "id": "94175", "point": "3", "event": "cff" } ], "support": [ { "name": "son", "id": "43468" }, { "name": "Jas", "id": "43552" } ] } ], "status_text": "success", "status_code": 200 }; const updateData = { "cards": [ { "iid": 154423, "number": 1, "name": "name", "sub_arr": [ { "name": "name", "id": "94184", "point": "6", "event": "ghd" } ], "support": [ { "name": "dson", "id": "43478" } ] } ] }; const mergedResult = deepMergeWithId(originalData, updateData); console.log(JSON.stringify(mergedResult, null, 2));
逻辑说明
mergeArraysById函数:将新数组转为ID映射表,遍历旧数组时用新数据覆盖同ID条目,同时补充旧数组没有的新条目,确保无重复。deepMergeWithId函数:- 针对顶层
cards数组,按iid匹配对应的卡片对象; - 对每个卡片内的
sub_arr和support子数组,调用mergeArraysById按id合并; - 非数组属性直接用更新数据覆盖,其他嵌套对象递归合并;
- 支持添加更新数据中新增的卡片条目。
- 针对顶层
运行示例后,合并结果会保留原有未被更新的所有条目,仅修改iid=154423卡片中id=94184的event值为ghd、id=43478的name值为dson,无重复条目。
内容的提问来源于stack exchange,提问作者msmreja
相关产品推荐
相关产品推荐

