
本文介绍如何根据对象中某个键(如 name)对数组中的多个对象进行分组,并合并各对象的非空字段,最终生成每个唯一键对应一个完整对象的结果数组。
本文介绍如何根据对象中某个键(如 `name`)对数组中的多个对象进行分组,并合并各对象的非空字段,最终生成每个唯一键对应一个完整对象的结果数组。
在实际开发中,我们常遇到数据分散存储的情况:同一实体(如学生)的信息被拆分成多条记录,每条仅填充部分字段,而关键标识字段(如 "name")相同。此时需将这些碎片化记录“拼合”为结构完整的单条对象。核心思路是:按 name 分组 → 对每组内各字段取首个非空值 → 合并为新对象。
以下是一个简洁、高效且可读性强的实现方案,使用 Array.prototype.reduce() 配合 ES2020 新增的 空值合并赋值运算符 ??= 和 逻辑或赋值运算符 ||=:
const obj = [
{ name: "A. Nasila", adm: "", class: "4p", mat: "80", eng: "", kis: "" },
{ name: "A. Nasila", adm: "4886", class: "", mat: "", eng: "", kis: "39" },
{ name: "Mtu Bure", adm: "", class: "3L", mat: "", eng: "86", kis: "" },
{ name: "A. Nasila", adm: "", class: "", mat: "", eng: "75", kis: "" },
{ name: "Mtu Bure", adm: "9790", class: "", mat: "77", eng: "", kis: "76" }
];
const merged = Object.values(
obj.reduce((acc, curr) => {
// 若该 name 尚未初始化,则创建空对象(仅当 acc[curr.name] 为 null 或 undefined 时触发)
acc[curr.name] ??= {};
// 遍历当前对象所有键,仅当目标位置尚无真值(非空字符串、非 0、非 true 等)时才赋值
Object.keys(curr).forEach(key => {
acc[curr.name][key] ||= curr[key];
});
return acc;
}, {})
);
console.log(merged);
// 输出:
// [
// { "name": "A. Nasila", "adm": "4886", "class": "4p", "mat": "80", "eng": "75", "kis": "39" },
// { "name": "Mtu Bure", "adm": "9790", "class": "3L", "mat": "77", "eng": "86", "kis": "76" }
// ]
✅ 关键说明:
- ??= 确保仅在 acc[curr.name] 为 null 或 undefined 时才初始化,避免覆盖已有对象;
- ||= 在字段值为 falsy(如 "", 0, false, null, undefined)时跳过赋值——注意:若业务允许 0 或 "0" 作为有效值,此方式不适用;此时应改用更精确的判断,例如 if (curr[key] !== "" && curr[key] != null)。
⚠️ 注意事项:
- 若字段可能包含 0、false 或 "0" 等有意义的 falsy 值,请勿直接使用 ||=,而应显式检查 curr[key] !== "" && curr[key] != null;
- name 字段必须存在且类型一致(建议提前校验),否则分组会失败;
- 此方法保留原始字段顺序(由 Object.keys() 遍历顺序决定),但不保证跨引擎完全一致;如需严格顺序,可预定义字段列表并按序合并。
该方案兼顾简洁性与实用性,适用于大多数表单补全、API 数据聚合等场景,是 JavaScript 中处理稀疏对象合并的经典范式。










