一、定义
reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。也就是说可以在给定初值的情况下,遍历数组中所有元素,执行reducer函数,并返回结果。
二、用法
arr.reduce(callback[, initialValue])
-
callback接收4个参数:您的 reducer 函数的返回值分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。
reducer = (acc, cur[, idx[, src]]) => { // function // 返回函数累计处理的结果 return acc }-
Accumulator (acc)(累计器)累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或
initialValue(见于下方)。- 传入
initialValue时,则acc=initialvalue,遍历从第0个元素开始 - 未传入
initialValue时,则acc=arr[0],遍历从第1个元素开始
let arr = [1,2,3,4,5] arr.reduce((acc, cur, idx) => { // 未传入初值,遍历从第1个元素开始,第一次时acc=1,cur=2 // 1,3,6,10,15 console.log(acc) return acc += cur }) arr.reduce((acc, cur, idx) => { // 传入初值0,遍历从第1个元素开始,第一次遍历时acc=0,cur=1 // 0,1,3,6,10,15 console.log(acc) return acc += cur }, 0) - 传入
-
Current Value (cur)(当前值)数组中正在处理的元素。
- 传入
initialValue时,则cur=arr[0],遍历从第0个元素开始 - 未传入
initialValue时,则crr=arr[1],遍历从第1个元素开始
let arr = [1,2,3,4,5] arr.reduce((acc, cur, idx) => { // 未传入初值,遍历从第1个元素开始 // 2,3,4,5 console.log(cur) }) arr.reduce((acc, cur, idx) => { // 传入初值0,遍历从第1个元素开始 // 1,2,3,4,5 console.log(cur) }, 0) - 传入
-
-
Current Index (idx)(当前索引)[可选]数组中正在处理的当前元素的索引。 如果提供了
initialValue,则起始索引号为0,否则为1let arr = [1,2,3,4,5] arr.reduce((acc, cur, idx) => { // 未传入初值,遍历从第1个元素开始 // 1,2,3,4 console.log(idx) }) arr.reduce((acc, cur, idx) => { // 传入初值0,遍历从第1个元素开始 // 0,1,2,3,4 console.log(idx) }, 0)
-
Source Array (src) (源数组)[可选]
调用
reduce()的数组 -
initialValue初始值作为第一次调用
callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用reduce将报错。
三、注意
reduce为数组中的每一个元素依次执行
callback函数,不包括数组中被删除或从未被赋值的元素let arr = [1,2,,4,5] // undefined、null都视为被赋值 arr.reduce((acc, cur, idx) => { // 未传入初值 // 1,3,4 console.log(idx) }) arr.reduce((acc, cur, idx) => { // 0,1,3,4 console.log(idx) }, 0)在没有初始值的空数组上调用
reduce将报错[].reduce((acc, cur, idx) => { // callback未执行,但有初始值,故返回初始值 console.log(idx) }, 0) [].reduce((acc, cur, idx) => { // callback未执行,没有初始值,报错 console.log(idx) }) // Uncaught TypeError: Reduce of empty array with no initial value未传入初始值,则
callback执行arr.length-1次,因为遍历从第1个元素遍历,acc=arr[0];传入初始值,则callback执行arr.length次,因为遍历从第0个元素遍历,acc=initialValue
四、拓展
1.initialValue为对象时,arr该如何变化?
- 传入初值
acc === initValue,故任何修改都不会影响arr
let arr = [{i: 1}, {i: 2}, {i: 3}]
let initialValue = {i: 0}
arr.reduce((acc, cur, idx) => {
// 直接修改acc, 即操作initialValue
acc.i += cur.i
return acc
}, initialValue)
// arr = [{i: 1}, {i: 2}, {i:3}]
// initialValue = {i:6}
- 未传入初值
acc === arr[0],对acc做任何运算,即相当于操作arr[0]
let arr = [{i: 1}, {i: 2}, {i: 3}]
arr.reduce((acc, cur, idx) => {
// 直接修改acc
acc.i += cur.i
return acc
})
// arr = [{i: 6}, {i: 2}, {i:3}]
// {i:6}
解决思路:不直接修改acc
let arr = [{i: 1}, {i: 2}, {i: 3}]
arr.reduce((acc, cur, idx) => {
// 返回新对象
return {i: acc.i + cur.i}
})
// arr = [{i: 1}, {i: 2}, {i:3}]
// {i:6}
结论:提供初始值initialValue更安全!
五、与其他方法进行对比
数组常用的遍历有
for、forEach、map、reduce、find、some、every等
1.遍历规则
- 已删除的项
都跳过已删除的项
- 未初始化的项
除了
find,其他的遍历都会跳过未初始化的项
let a = [1,null,,4,undefined,5,6]
a.find(item => {
console.log(item)
})
// 输出1,null,undefined,4,undefined,5,6
2.返回值
-
for为代码块,无返回值 -
forEach无返回值 -
map返回一个新数组,每个元素都是回调函数的结果。 -
reduce返回函数累计处理的结果,即acc -
find返回数组中第一个满足所提供测试函数的元素的值,否则返回undefined。 -
some如果回调函数返回至少一个数组元素的truthy值,则返回true;否则为false。 -
every如果回调函数的每一次返回都为truthy值,返回true,否则返回false。
六、应用场景
1.求累加和
let arr = [{i: 1}, {i: 2}, {i: 3}]
let initialValue = 0
initialValue = arr.reduce((acc, cur, idx) => {
return acc + cur.i
}, initialValue)
// initialValue = 6
2.将二维数组转换为一维数组
let arr = [[0,1],[2,3],[4,5]]
let initialValue = []
initialValue = arr.reduce((acc, cur, idx) => {
return [...acc,...cur]
}, initialValue)
// initialValue = [0,1,2,3,4,5]
3.计算数组中每个元素出现的次数
let arr = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice']
let initialValue = {}
initialValue = arr.reduce((acc, cur) => {
acc[cur] = (acc[cur] || 0 ) + 1
return acc
}, initialValue )
// initialValue = {Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
4.按属性对object分类
let arr = [{name: 'a', age: 18}, {name: 'b', age: 19}, {name: 'c', age: 18}, {name: 'd', age: 20}]
let groupBy = (objectArray, property) => {
return objectArray.reduce((acc, cur) => {
// 当前元素存在该属性
if (property in cur) {
acc[cur[property]] = acc[cur[property]] || []
acc[cur[property]].push(cur)
}
return acc
}, {})
}
// 根据age属性对arr分类
groupBy(arr, 'age')
/*
{
18: [{name: 'a', age: 18}, {name: 'c', age: 18}],
19: [{name: 'b', age: 19}],
20: [{name: 'd', age: 20}]
}
*/
5.数组去重
let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4]
arr.sort().reduce((acc, cur) => {
if (!acc.includes(cur)) {
acc.push(cur)
}
return acc
}, [])
// [1,2,3,4,5]
参考网址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce