👋 前言
在日常前端开发中,map
、filter
、forEach
我们都用得顺手,但一提到 reduce
,很多人马上露出"🤯懵"的表情。虽然 reduce
看起来像是"现代高级语法",但它其实早在 ES5(2009 年)就已经诞生了。
那一年,你可能还在用 IE8,但 reduce
已经在等你了 😎
我们常听到两种极端的说法:
- "
reduce
太高级了,看不懂就别用。" - "你这能用
reduce
,干嘛还写forEach
,显得不专业。"
那么问题来了:到底什么时候我们真的"需要" reduce
?它的优势到底是什么?
🧩 一句话解释:reduce
是"归并器"
reduce
的作用是:把一个数组变成一个值(这个值可以是数字、对象、数组、字符串......都可以)。
举个简单例子:
js
const nums = [1, 2, 3];
const sum = nums.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 6
没错,它可以"累加"。但 reduce
远不止加法那么简单。
🚀 用 reduce
可以做什么?
使用场景 | 示例 | 用不用 reduce |
---|---|---|
求和 | 数组求和 | ✅ 非常合适 |
统计 | 单词出现次数统计 | ✅ 高效 |
结构变换 | 数组转对象、转 Map | ✅ 优雅 |
嵌套结构处理 | 二维数组扁平化、树结构构建 | ✅ 函数式利器 |
简单遍历 | 单纯执行函数(无返回值) | ❌ 用 forEach 更合适 |
多条件过滤 | 保留某些元素 | ❌ 用 filter 更直接 |
🧠 举几个"值得用"的例子
✅ 1. 把数组变成对象(索引表)
js
const list = [
{ id: 'a1', name: '张三' },
{ id: 'b2', name: '李四' },
];
const map = list.reduce((acc, item) => {
acc[item.id] = item.name;
return acc;
}, {});
console.log(map);
// 👉 { a1: '张三', b2: '李四' }
比起先 forEach
然后一个个 map[item.id] = ...
,reduce
一步到位,清晰干净。
✅ 2. 分组统计
js
const items = [
{ type: 'A', count: 1 },
{ type: 'B', count: 2 },
{ type: 'A', count: 3 },
];
const grouped = items.reduce((acc, item) => {
acc[item.type] = (acc[item.type] || 0) + item.count;
return acc;
}, {});
console.log(grouped);
// 👉 { A: 4, B: 2 }
很难用 map
或 filter
做得更清楚,这种"合并累加"的需求,reduce
天生就适合。
✅ 3. 复杂嵌套数据处理
比如后端返回了一堆数据,要按 tab 分类:
js
const data = [
{ tab: 'A', value: 1 },
{ tab: 'B', value: 2 },
{ tab: 'A', value: 3 },
];
const tabMap = data.reduce((acc, item) => {
if (!acc[item.tab]) acc[item.tab] = [];
acc[item.tab].push(item.value);
return acc;
}, {});
得到:
css
{
A: [1, 3],
B: [2]
}
😵 为什么有些人觉得 reduce
很难用?
- 它"抽象"太强,
acc
是什么?cur
是谁?初始值又是啥? - 很多时候,只是为了"副作用"用它(比如
acc[x] = ...
),反而不如forEach
来得直观 - ESLint 常提示
no-param-reassign
,让初学者更混乱
🎯 那到底什么时候该用 reduce
?
总结一句话:
✅ 当你需要把一个数组"转化 "为一个值/对象/结构时,推荐用
reduce
❌ 如果只是遍历数组执行操作,不推荐用
reduce
,用forEach
更好
❌ 什么时候不要硬上 reduce
情况 1:只是单纯做副作用(比如设置值)
js
// ❌ 没必要用 reduce
arr.reduce((_, item) => {
doSomething(item);
}, null);
// ✅ 应该用 forEach
arr.forEach(item => doSomething(item));
情况 2:代码变得难以阅读
如果你要解释 3 层嵌套的 reduce
才能让别人理解,那就说明它不该用 reduce
,哪怕它写起来少几行。
🧘 小结
项目 | 推荐用 reduce 吗? | 理由 |
---|---|---|
数组求和 / 累加 | ✅ | 函数式最简洁 |
按条件聚合 | ✅ | 精准聚合逻辑 |
数据结构变换(如数组转对象) | ✅ | 直观可读 |
扁平化 / 转树结构 | ✅ | 表达能力强 |
执行副作用操作(不返回值) | ❌ | 用 forEach 更清楚 |
只是过滤 | ❌ | 用 filter 简单直接 |
📘 reduce
这个名字是怎么来的?它英文到底什么意思?
有时候我们学一个 API,会忍不住问:
"为什么叫它
reduce
?不是叫sumUp
、combine
、fold
呢?"
其实它确实是有语义基础的。
reduce
是英文中的动词,意思是:
"to make something smaller or simpler"
------「使某物减少、缩小、简化」
🔤 常见的英文用法举例:
reduce noise
👉 降噪reduce cost
👉 降低成本reduce weight
👉 减肥reduce a problem to its essence
👉 把问题简化成本质
🧠 在 JavaScript 中,reduce
就是这个含义的编程表达:
js
[1, 2, 3, 4] → 10 // 数字
[1, 2, 3] → {1: true, 2: true, 3: true} // 对象
也就是说:
reduce
是把"一堆数据"归约成"一个值",是从"多个" → "一个"的过程,是一种简化、压缩、归纳。
✅ 英文语义与代码行为对照:
英文语境 | 编程中的含义 |
---|---|
reduce noise | 清洗、精简数据 |
reduce cost | 减少资源或运行消耗 |
reduce complexity | 简化代码结构 |
reduce (数组) | 将数组转化为一个目标结构 |
所以这个 API 不是随便起名的,它的语义就是 "压缩"、"归并"、"总结"!
🧪 最后,给你一个面试/练手题
用
reduce
实现一个函数,把数组[1, 2, 3, 4]
转成{ 1: true, 2: true, 3: true, 4: true }
总结
reduce
是一个很强大的工具,但不是什么都要reduce
。当你真正"需要把数组折叠成一个结构 "时,
reduce
能让你写出 少但更强的代码。
如果你觉得这篇文章对你有帮助,别忘了点赞 + 收藏
欢迎关注我,我会持续分享实战中的高质量前端知识!