
本文详解如何利用 array.prototype.reduce 高阶函数高效统计数组中每个元素的出现频次,提供可直接运行的代码示例、关键逻辑解析及常见注意事项。
本文详解如何利用 array.prototype.reduce 高阶函数高效统计数组中每个元素的出现频次,提供可直接运行的代码示例、关键逻辑解析及常见注意事项。
在 JavaScript 中,reduce() 是一个功能强大且富有表现力的数组迭代方法,适用于将数组“归约”为单一值(如对象、数字或字符串)。统计数组中各元素出现次数,正是 reduce() 的典型应用场景——它能以声明式、无副作用的方式替代传统 for 循环,提升代码可读性与可维护性。
核心实现原理
我们通过 reduce() 构建一个计数映射对象(count map):
- 初始累加器(acc)设为空对象 {};
- 每次遍历当前元素(curr),检查 acc[curr] 是否已存在:
- 若不存在(undefined 或 falsy),初始化为 0;
- 然后统一执行 acc[curr] += 1;
- 最终返回更新后的 acc,完成累积。
以下是完整可运行示例:
const array = [1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 1, 2, 3, 1, 2, 3, 3, 3, 3, 3, 4, 98, -546, 4];
const countMap = array.reduce((acc, curr) => {
acc[curr] = (acc[curr] || 0) + 1;
return acc;
}, {});
console.log(countMap);
// 输出:
// {
// '1': 4, '2': 4, '3': 8, '4': 3, '5': 1,
// '6': 1, '7': 1, '98': 1, '-546': 1
// }✅ 技巧优化:相比 if (!acc[curr]) acc[curr] = 0,使用 (acc[curr] || 0) + 1 更简洁且语义清晰,同时兼容 0、null、undefined 等 falsy 值场景。
立即学习“Java免费学习笔记(深入)”;
注意事项与最佳实践
-
键类型自动转换:对象属性名始终为字符串,因此数字 -546 会转为 '-546',布尔值 true 变为 'true'。若需保持原始类型(如区分 1 和 '1'),应改用 Map:
const countMap = array.reduce((acc, curr) => { acc.set(curr, (acc.get(curr) || 0) + 1); return acc; }, new Map()); 避免突变外部状态:确保 reduce 回调中只操作并返回 acc,不修改原数组或外部变量,以维持纯函数特性。
性能考量:对超大数组(>10⁵ 元素),reduce 与 for 循环性能接近;但 reduce 更具可组合性(例如后续链式调用 .entries() 或 .filter())。
总结
reduce 并非仅用于求和或拼接——它本质是“状态累积器”。掌握其在频次统计中的应用,是理解函数式编程思维的关键一步。从初学者的 for 循环过渡到 reduce,不仅是语法升级,更是对数据流抽象能力的提升。建议在实际项目中优先使用该模式,并结合 TypeScript 类型注解增强健壮性(如 Record<string, number>)。









