
本文介绍如何将键值为对象的普通 javascript 对象,按指定属性(如 name)进行去重分组,并生成带计数的新对象,输出结果保持数字索引顺序。
本文介绍如何将键值为对象的普通 javascript 对象,按指定属性(如 name)进行去重分组,并生成带计数的新对象,输出结果保持数字索引顺序。
在实际开发中,我们常遇到类似场景:一个类数组对象(即键为连续数字字符串的普通对象)存储了多条记录,需按某字段(如 Name)聚合统计出现次数,并以紧凑、有序的结构重新组织数据。虽然输入看似像数组,但它本质是对象,因此不能直接使用 Array.prototype 方法,需先通过 Object.values() 提取值,再进行处理。
以下是清晰、高效且兼容性良好的实现方案:
const input = {
0: { State: true, Name: 'bob' },
1: { State: true, Name: 'candice' },
2: { State: true, Name: 'allen' },
3: { State: true, Name: 'bob' },
4: { State: true, Name: 'bob' },
5: { State: true, Name: 'candice' }
};
// 步骤 1:按 Name 统计频次(使用空值合并操作符 ?? 确保初始值为 0)
const countMap = {};
for (const { Name } of Object.values(input)) {
countMap[Name] = (countMap[Name] ?? 0) + 1;
}
// 步骤 2:转换为按数字索引排列的目标格式
const result = {};
Object.entries(countMap).forEach(([Name, Count], index) => {
result[index] = { Name, Count };
});
console.log(result);
// 输出:
// {
// 0: { Name: 'bob', Count: 3 },
// 1: { Name: 'candice', Count: 2 },
// 2: { Name: 'allen', Count: 1 }
// }
✅ 关键要点说明:
- 使用 Object.values(input) 安全提取所有值,避免遍历原型链或非数字键干扰;
- ?? 0 比 || 0 更严谨,能正确处理 countMap[Name] 为 0(falsy 但有效)的情况;
- Object.entries() 返回 [key, value] 数组,天然保持插入顺序(ES2015+ 规范保证),确保 'bob'、'candice'、'allen' 的输出顺序与首次出现顺序一致(若需严格按频次降序,可额外调用 .sort());
- 最终结构使用数字字符串键('0', '1'…),符合原始需求,也便于后续作为类数组结构消费(例如 for...in 或 Object.keys(result).map(...))。
⚠️ 注意事项:
- 若输入对象键不连续(如含 '100'、'abc'),Object.values() 仍可靠;但若需保留原始索引语义,请明确业务逻辑是否依赖键顺序;
- 如需支持 IE 浏览器,可将 ?? 替换为 countMap[Name] === undefined ? 0 : countMap[Name];
- 若数据量极大(万级),可考虑 Map 替代普通对象提升性能,但对一般场景无明显收益。
该方案简洁、可读性强,无需引入外部库,兼顾现代语法与向后兼容性,是解决此类“对象频次扁平化”问题的推荐实践。











