reduce是JavaScript数组中功能强大且易被低估的方法,通过累加器逐步处理元素并返回单个值;需传入回调函数和可选初始值,常用于累加、分组统计、多维度聚合等场景,使用时需注意空数组、返回值、副作用及精度问题。

reduce 是 JavaScript 数组中功能最强大、也最容易被低估的方法之一。它不直接做累加,而是通过一个“累加器”(accumulator)逐步处理每个元素,最终返回单个值——这个值可以是数字、对象、数组,甚至 Promise。
基础累加:从零开始理解 reduce 的执行逻辑
调用 reduce 至少需要两个参数:一个回调函数和一个可选的初始值(initialValue)。回调函数接收四个参数,但最常用的是前两个:accumulator(累加器) 和 currentValue(当前项)。
没有提供初始值时,第一次调用会把数组第一个元素作为 accumulator,第二个元素作为 currentValue;提供初始值后,accumulator 从该值开始,currentValue 从第一个元素开始遍历。
例如对 [1, 2, 3, 4] 求和:
立即学习“Java免费学习笔记(深入)”;
[1, 2, 3, 4].reduce((sum, num) => sum + num, 0); // 10 // 执行过程: // sum=0, num=1 → 1 // sum=1, num=2 → 3 // sum=3, num=3 → 6 // sum=6, num=4 → 10
按条件分组聚合:构建对象结构的统计结果
当需要将数组按某个字段(如 category、status)归类并统计时,reduce 比 filter + map 组合更简洁高效。关键是让 accumulator 初始为一个空对象 {},并在每次迭代中更新对应 key 的值。
示例:按类型统计商品数量
const items = [
{ name: '苹果', type: '水果' },
{ name: '香蕉', type: '水果' },
{ name: '牛奶', type: '乳品' }
];
const grouped = items.reduce((acc, item) => {
const { type } = item;
acc[type] = (acc[type] || 0) + 1;
return acc;
}, {});
// 结果:{ 水果: 2, 乳品: 1 }
- 每次迭代都检查
acc[type]是否存在,不存在则设为 0 再加 1 - 务必记得 return acc,否则下一轮 acc 变成 undefined
- 如果想收集完整子数组(不止计数),可写成
acc[type] = [...(acc[type] || []), item]
嵌套结构扁平化与多维度聚合
面对树形数据、多层嵌套或需同时计算多个指标(如总和、平均值、最大值)的情况,reduce 依然适用——只需让 accumulator 是一个结构清晰的对象。
示例:计算学生成绩的总分、最高分、平均分
const scores = [85, 92, 78, 96, 88];
const stats = scores.reduce(
(acc, score) => ({
sum: acc.sum + score,
max: Math.max(acc.max, score),
count: acc.count + 1,
avg: null // 先留空,最后再算
}),
{ sum: 0, max: -Infinity, count: 0 }
);
stats.avg = stats.sum / stats.count; // 87.8
- accumulator 不必是简单类型,对象或数组均可,关键是一致性
- 避免在 reduce 中做耗时操作(如深克隆、DOM 查询),保持纯函数特性
- 若需异步聚合(如等待多个 API 返回后再合并),可配合
Promise.all预先请求,再用 reduce 整理结果
常见陷阱与健壮写法建议
reduce 强大但容易出错,尤其在边界情况处理上。
-
空数组无初始值 → 报错:必须传 initialValue,或提前判断
arr.length === 0 - 忘记 return 导致后续迭代失败:箭头函数单行表达式隐式返回,但多语句必须显式写 return
- 修改原对象/数组引发副作用:不要在 reduce 回调里 push/splice 原数组,应创建新对象或使用扩展运算符
-
浮点数精度问题:累加小数时注意
(0.1 + 0.2) !== 0.3,必要时用parseFloat((a + b).toFixed(10))


















