介绍Reduce函数
reduce为数组中的每一个元素依次执行callback函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:
accumulator累计器currentValue当前值currentIndex当前索引array数组
回调函数第一次执行时,accumulator 和currentValue的取值有两种情况:如果调用reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;如果没有提供initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。
注意:如果没有提供initialValue,reduce会从索引1的地方开始执行callback方法,跳过第一个索引。如果提供initialValue,从索引0开始。
Reduce原理
Array.prototype.myReduce = function (callback, initialValue) {
let accumlator = initialValue ? initialValue : undefined
for (let i = 0; i < this.length; i++) {
if (accumlator) {
accumlator = callback.call(undefined, accumlator, this[i], i, this);
} else {
accumlator = this[i]
}
}
return accumlator
}
const arr = [10, 20, 30, 40]
const total = arr.myReduce((prev, cur)=>{
return prev + cur
}, 10)
console.log(total)
Reduce用例
获取对象属性之和
const data = [
{ times: 2, round: 3 },
{ times: 1, round: 4 },
{ times: 6, round: 8 },
]
// 方法1,先算单项,再合并
const keys = Object.keys(data[0])
const sum = {}
keys.forEach((item) => {
const subSum = data.reduce((prev, cur)=> {
return prev + cur[item]
}, 0)
sum[item] = subSum
})
console.log('sum', sum)
// 方法2,先给初始值,再累加
const result = data.reduce((prev, cur) => {
for (const i in cur) {
if (!prev[i]) {
prev[i] = 0
}
prev[i] += cur[i]
}
return prev
}, {})
console.log('result', result)
按比例获取属性之和
const data = [
{
subject: 'math',
score: 88
},
{
subject: 'chinese',
score: 95
},
{
subject: 'english',
score: 80
}
]
const proportion = {
math: 0.5,
chinese: 0.3,
english: 0.2
}
const result = data.reduce((prev, cur) => {
return prev + cur['score'] * proportion[cur['subject']]
}, 0)
console.log('result', result)
获取字符出现的次数
const arrStr = 'abcdaabc';
const result = arrStr.split('').reduce((prev, cur)=>{
prev[cur] ? prev[cur]++ : prev[cur] = 1
return prev
}, {})
console.log('result', result)
数组去重
const arr = [1,2,4,4,1]
const result = arr.reduce((prev, cur)=>{
if(Array.isArray(prev) && !prev.includes(cur)) {
prev.push(cur)
}
return prev
}, [])
console.log('result', result)
将二维数组转为一维
const data = [[0, 1], [2, 3], [4, 5]]
const result = data.reduce((prev, cur)=>{
if (Array.isArray(prev)) {
return prev.concat(cur)
}
}, [])
console.log('result', result)
将多维数据转为一维
const data = [[0, 1], [2, 3], [4, [5, 6, 7]]]
// 方法1, 遍历
const result = data.reduce((prev, cur)=> {
if (Array.isArray(prev)) {
for (const i of cur) {
if (Array.isArray(i)) {
prev = prev.concat(i)
} else {
prev.push(i)
}
}
}
return prev
}, [])
console.log('result', result)
// 方法2,递归
const newArr = (arr) => {
return arr.reduce((pre,cur)=>
pre.concat(Array.isArray(cur)?newArr(cur):cur)
,[])}
console.log(newArr(data))
找到最大值
const dates = [
'2019/06/01',
'2018/06/01',
'2019/09/01',
'2018/09/01'
].map(v => new Date(v));
const result = dates.reduce((prev, cur)=> {
return prev > cur ? prev : cur
}, dates[0])
console.log('result', result)
链式调用promise
const functions = [
async function() { return 1; },
async function() { return 2; },
async function() { return 3; }
]
const result = await functions.reduce((promise, fn)=> {
return promise.then(fn)
}, Promise.resolve())
console.log('result', result)