目录
- [一、reduce 是什么?](#一、reduce 是什么?)
- 二、核心参数解析
-
- 回调函数参数:
- initialValue(重点)
-
- [有 initialValue](#有 initialValue)
- [没有 initialValue](#没有 initialValue)
- [三、reduce 执行机制(面试重点🔥)](#三、reduce 执行机制(面试重点🔥))
- [四、手写 reduce](#四、手写 reduce)
- [五、reduce 的 5 大核心用途](#五、reduce 的 5 大核心用途)
-
- 求和:
- 数组扁平化(flat):
- 计数统计:
- 数组转对象:
- [实现 map / filter(进阶):](#实现 map / filter(进阶):)
- [六、reduce 面试高频考点](#六、reduce 面试高频考点)
-
- [reduce 和 map 的区别?](#reduce 和 map 的区别?)
- [reduce 如果不传 initialValue 会怎样?](#reduce 如果不传 initialValue 会怎样?)
- [reduce 是否改变原数组?](#reduce 是否改变原数组?)
- [空数组调用 reduce 会怎样?](#空数组调用 reduce 会怎样?)
- [七、reduce 易错点](#七、reduce 易错点)
-
- [1. 忘记 initialValue](#1. 忘记 initialValue)
- [2. acc 类型混乱](#2. acc 类型混乱)
- [3. return 忘写](#3. return 忘写)
- [4. 修改 acc(副作用)](#4. 修改 acc(副作用))
- 九、面试杀手题
-
- [用 reduce 实现 flat](#用 reduce 实现 flat)
- [用 reduce 实现 Promise 串行](#用 reduce 实现 Promise 串行)
- 总结:
一、reduce 是什么?
reduce就是把数组"归并"为一个值(任意类型) (reduce = for 循环 + 累加器)
js
arr.reduce((acc, cur, index, array) => {
return acc + cur
}, initialValue)
二、核心参数解析
回调函数参数:
| 参数 | 含义 |
|---|---|
| acc | 累加器(核心) |
| cur | 当前值 |
| index | 当前索引 |
| array | 原数组 |
initialValue(重点)
有 initialValue
javascript
[1,2,3].reduce(fn, 10)
执行:
javascript
acc = 10
cur = 1
👉 从 index = 0 开始
没有 initialValue
javascript
[1,2,3].reduce(fn)
执行:
javascript
acc = 1(自动取 this[0])
cur = 2
👉 从 index = 1 开始
结论:给了初始值从第0项开始加,第一项是 initialValue;没给初始值第0项默认为初始值,从第一项开始添加。
三、reduce 执行机制(面试重点🔥)
执行流程:
- 初始化 acc
- 遍历数组
- 每次更新 acc
- 返回最终 acc
本质模型:
javascript
acc = fn(acc, cur)
四、手写 reduce
javascript
Array.prototype.myReduce = function(fn, init) {
let acc = init ?? this[0];
let start = init ? 0 : 1;
for (let i = start; i < this.length; i++) {
acc = fn(acc, this[i], i, this)
}
return acc
}
五、reduce 的 5 大核心用途
求和:
javascript
[1,2,3].reduce((a,b) => a + b, 0)
数组扁平化(flat):
javascript
[[1,2],[3,4]].reduce((a,b) => a.concat(b), [])
计数统计:
javascript
['a','b','a'].reduce((acc, cur) => {
acc[cur] = (acc[cur] || 0) + 1
return acc
}, {})
输出:
javascript
{ a: 2, b: 1 }
数组转对象:
javascript
[
{ id: 1, name: 'A' },
{ id: 2, name: 'B' }
].reduce((acc, cur) => {
acc[cur.id] = cur
return acc
}, {})
实现 map / filter(进阶):
- map
使用map实现:
javascript
[1,2,3].map(x => x * 2)
使用reduce实现:
javascript
arr.reduce((acc, cur) => {
acc.push(cur * 2)
return acc
}, [])
- filter
使用filter实现:
javascript
[1,2,3].filter(x => x > 1)
使用reduce实现:
javascript
arr.reduce((acc, cur) => {
if (cur > 1) acc.push(cur)
return acc
}, [])
六、reduce 面试高频考点
reduce 和 map 的区别?
| 方法 | 作用 |
|---|---|
| map | 一对一转换 |
| reduce | 任意归并 |
reduce 如果不传 initialValue 会怎样?
使用数组第一个元素;从 index = 1 开始
reduce 是否改变原数组?
不改变!!!!
空数组调用 reduce 会怎样?
javascript
[].reduce(fn)
会报错!TypeError: Reduce of empty array with no initial value
七、reduce 易错点
1. 忘记 initialValue
javascript
[].reduce(fn) // ❌ 报错
2. acc 类型混乱
javascript
[1,2,3].reduce((a,b) => a + b, {})
类型错误!!!
3. return 忘写
javascript
reduce((acc, cur) => {
acc + cur // ❌ 没 return
})
4. 修改 acc(副作用)
javascript
acc.push(cur) // ⚠️ 需要注意引用类型
九、面试杀手题
用 reduce 实现 flat
javascript
function flat(arr) {
return arr.reduce((acc, cur) => {
return acc.concat(Array.isArray(cur) ? flat(cur) : cur)
}, [])
}
用 reduce 实现 Promise 串行
javascript
function runTasks(tasks) {
return tasks.reduce((prev, task) => {
return prev.then(() => task())
}, Promise.resolve())
}
总结:
reduce 是一个"把数组通过累加器转换成任意结果"的高阶函数,本质是 for 循环 + acc 累积模型。