
本文介绍一种简洁高效的方案,用于比对两个具有嵌套对象结构的数组(如旧数组中每个元素含 item 字段,新数组为扁平对象),根据 ID 合并状态(保留已有 active 值,新增项默认 active: false)。
本文介绍一种简洁高效的方案,用于比对两个具有嵌套对象结构的数组(如旧数组中每个元素含 `item` 字段,新数组为扁平对象),根据 id 合并状态(保留已有 `active` 值,新增项默认 `active: false`)。
在实际开发中,我们常需基于 ID 对两个结构不完全一致但语义关联的数组进行“状态同步”——例如前端维护一份带业务状态(如 active)的列表,后端返回更新后的基础数据(仅含 id 和 path 等字段),此时需智能合并:保留原状态、剔除过期项、注入新增项并赋予默认状态。
核心思路是:
- 从旧数组中提取所有已存在的 item.id,构建 Set 以支持 O(1) 查找;
- 遍历新数组,对每个对象判断其 id 是否存在于旧数组中;
- 若存在,则复用旧数组中对应项的 active 值;否则设为 false;
- 将新对象包装为 { item, active } 格式,构成最终结果。
以下是完整可运行的实现:
const oldItems = [
{ item: { id: '1', path: "some text" }, active: true },
{ item: { id: '2', path: "some text" }, active: true },
{ item: { id: '4', path: "some text" }, active: false },
{ item: { id: '10', path: "some text" }, active: false }
];
const newItems = [
{ id: '1', path: "some text" },
{ id: '4', path: "some text" },
{ id: '6', path: "some text" }
];
// 步骤1:提取旧数组中所有 item.id
const existingIds = new Set(oldItems.map(obj => obj.item.id));
// 步骤2:映射新数组,按ID决定active状态
const result = newItems.map(item => ({
item,
active: existingIds.has(item.id)
}));
console.log(result);
// 输出:
// [
// { item: { id: '1', path: "some text" }, active: true },
// { item: { id: '4', path: "some text" }, active: false },
// { item: { id: '6', path: "some text" }, active: false }
// ]
✅ 关键优势:
- 时间复杂度为 O(n + m),远优于嵌套循环的 O(n×m);
- 无副作用,纯函数式风格,便于测试与复用;
- 自动处理新增/保留/忽略(非新增且不在新数组中的项自然被排除)。
⚠️ 注意事项:
- 该方案不保留旧数组中存在但新数组中缺失的项(如 id: '2' 和 '10' 被移除),符合题设“只保留新数组中的 ID”要求;
- 若需保留旧状态(如 id: '2' 的 active: true)并仅更新交集,应改用 filter + find 或 Map 索引优化;
- id 类型需严格一致(字符串 vs 数字),建议统一转换(如 String(item.id))以防隐式转换导致匹配失败。
总结:当面对“新数据驱动、旧状态继承”的数组同步场景时,利用 Set 预索引 + map 映射是最轻量、最可读、最高效的解法。










