🧠【彻底读懂 reduce】acc 是谁?我是谁?我们要干嘛?

🚧 开场:把你困住的误解先拆了

你是不是也以为:

"acc 是数组的每一项吗?是不是就相当于数组里的那个元素?"

答案是------不是!不是!真的不是!

让我们用这篇文章,从「误解」出发,到「掌握精髓」收官,完成一次技术脑内革命!


🏷️ 一、reduce 是什么?------数组界的「炼丹炉」

你可以把 reduce 理解为一口循环不断的炼丹炉

🌰 经典语法结构:

javascript 复制代码
arr.reduce((acc, cur, index, array) => {
  return 新的 acc;
}, 初始值);
  • acc(累计器):每一次处理的中间产物,也就是"丹药"
  • cur:数组当前项,是"投进去的新材料"
  • return 的值会变成下一次的 acc
  • 初始值:就是最开始丢进去的那一勺清水/引子

☕ 巧记口诀:

初始入炉为丹引,

每步炼化靠 acc,

一路处理到尾项,

千形万象终归一!


🤯 二、那 acc 到底是什么?

很多人以为 acc 是数组每个值,但 它其实是你自己 return 出来的中间结果

看个例子就明白了:

javascript 复制代码
[1, 2, 3].reduce((acc, cur) => {
  console.log('acc:', acc, 'cur:', cur);
  return acc + cur;
}, 0);

👉 输出如下:

makefile 复制代码
acc: 0 cur: 1
acc: 1 cur: 2
acc: 3 cur: 3

最后返回 6!

你看见了吗?

  • acc 初始是 0
  • 第一轮:0 + 1 = 1,传给下一轮
  • 第二轮:1 + 2 = 3
  • 第三轮:3 + 3 = 6

acc 是你一手打造、一手维护、一手传承的"结果容器"。


📌 终极记忆法:

acc 是你"自己做出来"的,cur 是数组"送过来的"。


🧪 三、reduce 常见实战用法(带巧计)

1️⃣ 数组求和(基础)

ini 复制代码
[1, 2, 3, 4].reduce((acc, cur) => acc + cur, 0);

💡 巧计:acc 是你口袋的余额,cur 是你捡到的零钱。


2️⃣ 统计频次(中级)

scss 复制代码
['🍎', '🍌', '🍎'].reduce((acc, cur) => {
  acc[cur] = (acc[cur] || 0) + 1;
  return acc;
}, {});

💡 巧计:acc 是记账本,cur 是进店顾客,来一位就打正字。


3️⃣ 按类型分组(高级)

ini 复制代码
const list = [
  { name: '小明', group: 'A' },
  { name: '小红', group: 'B' },
  { name: '小刚', group: 'A' },
];
const grouped = list.reduce((acc, cur) => {
  (acc[cur.group] ||= []).push(cur);
  return acc;
}, {});

💡 巧计:acc 是教室,cur 是学生,按班级安排座位。


4️⃣ 扁平化数组(进阶)

lua 复制代码
[[1, 2], [3, 4], [5]].reduce((acc, cur) => acc.concat(cur), []);

💡 巧计:acc 是铺平的地面,cur 是被压扁的山丘。


5️⃣ 实现 map 和 filter(黑魔法)

ini 复制代码
// map
arr.reduce((acc, cur) => {
  acc.push(cur * 2);
  return acc;
}, []);

// filter
arr.reduce((acc, cur) => {
  if (cur % 2 === 0) acc.push(cur);
  return acc;
}, []);

💡 巧计:

map 是换头术,filter 是拣人术,reduce 是百变术!


⚔️ 四、和其他数组方法比个高低

函数 功能 返回值类型 可中断 初始值 灵活性
forEach 只执行遍历 无(undefined) 🚫
map 一对一映射 数组
filter 条件筛选 数组
some/every 条件判断 Boolean 🚫
reduce 多合一转化 任意类型 ✅✅✅

🎯 结论:reduce 是 JS 数组操作界的「全能选手」,其他方法做不到的,它都能!


🧬 五、底层实现你也能写!

模拟原生 reduce 的核心逻辑 👇

ini 复制代码
Array.prototype.myReduce = function (cb, initialValue) {
  let acc = initialValue;
  let i = 0;
  const arr = this;

  if (acc === undefined) {
    if (!arr.length) throw new TypeError('空数组没初始值');
    acc = arr[0];
    i = 1;
  }

  for (; i < arr.length; i++) {
    acc = cb(acc, arr[i], i, arr);
  }

  return acc;
};

💣 小心炸点:

css 复制代码
[].reduce((a, b) => a + b); // ❌ 报错
[].reduce((a, b) => a + b, 0); // ✅ 返回 0

🔮 六、哲学升华 & 函数式世界里的 reduce

reduce 就是一条"函数管道",把每一步处理的结果传给下一步,直到最终收束。

javascript 复制代码
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);

在 redux 中间件、koa 洋葱模型、Vue 插件链......都能看到 reduce 的影子。

🌌 它是一种思维方式:组合、累积、转化、递进。


🧨 七、终极巧记总结

🥋 再念一遍口诀:

reduce 是个炼丹炉,

入料为你定起初;

acc 是丹,cur 是火,

一路熬来百变出。


🎁 彩蛋题:flatten 多维数组

ini 复制代码
const flatten = arr => arr.reduce((acc, cur) => {
  return acc.concat(Array.isArray(cur) ? flatten(cur) : cur);
}, []);

✅ 你现在应该已经掌握了:

  • ✅ acc 的本质(不是数组项,是 return 出来的中间结果)
  • ✅ reduce 的运行机制
  • ✅ 各种实战场景及巧妙类比
  • ✅ 和其他方法的核心区别
  • ✅ 自己实现 reduce
  • ✅ reduce 在函数式中的地位

👇 最后,如果你还记得最初的问题:

"acc 是数组里的每一项吗?"

你应该可以坚定地回答:

不是!acc 是我 return 出来的结果,是我的魂,是我的锤,是我整个计算的载体!

相关推荐
倔强青铜三25 分钟前
苦练Python第9天:if-else分支九剑
人工智能·python·面试
江城开朗的豌豆30 分钟前
Vue计算属性:为什么我的代码突然变优雅了?
前端·javascript·vue.js
Sun_light39 分钟前
5 个理由告诉你为什么有了 JS 还要用 TypeScript
前端·typescript
前端拿破轮39 分钟前
翻转字符串里的单词,难点不是翻转,而是正则表达式?💩💩💩
算法·leetcode·面试
陈随易41 分钟前
Kimi k2发布,效果比肩Sonnet4,价格与DeepSeek一致
前端·后端·程序员
_一条咸鱼_42 分钟前
LangChain多模态提示词设计探索的源码级深度剖析(16)
人工智能·面试·langchain
倔强青铜三43 分钟前
苦练Python第8天:while 循环之妙用
人工智能·python·面试
心.c1 小时前
后台管理系统-权限管理
javascript·react.js·github
_一条咸鱼_1 小时前
LangChain输出解析器的作用与类型解析(17)
人工智能·面试·langchain
_一条咸鱼_1 小时前
Android Runtime内存共享与访问控制原理剖析(71)
android·面试·android jetpack