
本文详解如何在 JavaScript 中实现基于 key(尤其是子数组中 id 字段)的智能深度合并,解决 cards 数组中同 iid 对象的精准更新、sub_arr 和 support 等嵌套数组按 id 合并去重等核心问题,避免 lodash 默认 merge 产生的重复项。
本文详解如何在 javascript 中实现**基于 key(尤其是子数组中 id 字段)的智能深度合并**,解决 `cards` 数组中同 `iid` 对象的精准更新、`sub_arr` 和 `support` 等嵌套数组按 `id` 合并去重等核心问题,避免 lodash 默认 merge 产生的重复项。
在实际业务开发中(如卡片式数据管理、实时同步接口响应),我们常需将「增量更新数据」与「原始完整数据」进行深度合并——但标准的 Object.assign()、展开运算符(...)或 _.merge() 都无法满足「按 id 精准替换子数组元素」的需求。例如:原始 cards[0].sub_arr 包含 3 个对象(id: "94184", "90363", "94185"),而更新数据仅提供 id: "94184" 的新 event 值;此时我们期望的结果是:保留原数组结构,仅更新匹配 id 的条目,不追加、不覆盖整个数组,更不产生重复。
为此,我们需要一个可配置键名(如 "id")的深度合并函数,其核心逻辑需分层处理:
- 对顶层对象属性:执行常规深度递归合并;
- 对数组类型属性(如
sub_arr,support):启用「ID 映射合并」策略——先将原数组转为Map<id item></id>,再用更新数组逐项set()覆盖,最后还原为数组。
以下是生产就绪的实现方案:
/**
* 按指定 key(如 'id')深度合并两个对象,对数组自动去重更新
* @param {Object} target - 目标对象(被修改)
* @param {Object} source - 源对象(提供更新)
* @param {string} [idKey='id'] - 用于识别唯一性的字段名(适用于数组元素)
* @returns {Object} 合并后的 target
*/
function deepMergeById(target, source, idKey = 'id') {
if (target === null || source === null || typeof target !== 'object' || typeof source !== 'object') {
return source;
}
// 遍历 source 的每个属性
for (const key in source) {
if (!source.hasOwnProperty(key)) continue;
const targetVal = target[key];
const sourceVal = source[key];
// 场景1:双方均为对象且非数组 → 递归深度合并
if (
sourceVal !== null &&
typeof sourceVal === 'object' &&
!Array.isArray(sourceVal) &&
targetVal !== null &&
typeof targetVal === 'object' &&
!Array.isArray(targetVal)
) {
deepMergeById(targetVal, sourceVal, idKey);
}
// 场景2:双方均为数组 → 按 idKey 合并(去重更新)
else if (Array.isArray(targetVal) && Array.isArray(sourceVal)) {
// 构建 id → item 映射
const map = new Map(targetVal.map(item => [item[idKey], item]));
// 用 source 数组逐项覆盖
sourceVal.forEach(item => {
if (item && typeof item === 'object' && idKey in item) {
map.set(item[idKey], { ...map.get(item[idKey]), ...item });
}
});
// 还原为数组(保持原始顺序 + 新增项置后)
target[key] = Array.from(map.values());
}
// 场景3:基础类型或单值覆盖(字符串、数字、null 等)
else {
target[key] = sourceVal;
}
}
return target;
}
// ✅ 使用示例
const original = { /* 你的原始 object1 */ };
const update = { /* 你的更新 object2 */ };
deepMergeById(original, update, 'id'); // 指定 'id' 为唯一标识字段
console.log(original.cards[0].sub_arr);
// 输出:[{ id: "94184", name: "name", point: "6", event: "ghd" }, ... 其余未变项]
? 关键设计说明:
Alibabacloud Sdk Client Initialization For Java下载在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
Map保证 O(1) 查找与无序去重:避免findIndex循环遍历,提升大数据量性能;- 浅拷贝合并
{...map.get(), ...item}:确保只覆盖source提供的字段,保留原对象其他属性;- 新增
id条目自动追加:若source中某id在target中不存在,则直接插入,符合增量更新语义;- 支持任意层级嵌套:只要某层是数组且含
idKey字段,即触发 ID 合并逻辑。
⚠️ 注意事项:
- 若数组元素不含
idKey字段(如undefined或缺失),该条目将被跳过,不会报错; - 此函数直接修改
target(符合Object.assign习惯),如需不可变更新,请先structuredClone(target)(现代环境)或深拷贝后再传入; - 浏览器兼容性:
structuredClone支持 Chrome 98+/Firefox 94+/Safari 15.4+;旧环境请搭配lodash.cloneDeep或 JSON 序列化方案(注意Date/Map/Set等不可序列化类型)。
✅ 对比验证:运行上述代码后,original.cards[0].sub_arr 中 id: "94184" 的 event 将正确更新为 "ghd",id: "90363" 和 "94185" 保持不变,且不会出现重复对象——这正是业务场景所要求的「精准、可控、无副作用」的深度合并能力。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











