一、概述
参考:-MDN web docs
Array.prototype.reduce()
reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。reduce是ES5中新增的又一个数组逐项处理方法
const arr = [1, 2, 3, 4];
const result = arr.reduce((accumulator, currentValue) => accumulator + currentValue)
1 + 2 + 3 + 4
console.log(result) // 10
Array.reduce(reducer) reducer函数接收4个参数:
- accumulator(acc)累计器
- currentValue(cur)当前值
- curerntIndex(idx)当前索引
- sourceArray(src)源数组
二、语法
reduce的使用方法:
arr.reduce(callback(acc, cur[, idx[, src]])[,initalValue])
参数:
callback: 执行数组中每个值的函数(如果没有初始值initalValue则第一个除外),其有四个参数:
acc:累计器累计回调的返回值;踏实上一次调用回调时返回的累积值,或者initalValue
cur:数组中正在处理的元素
idx:(可选)数组中正在处理的当前元素的索引,(如果提供了initialValue,则起始索引号为0,否则从索引1起始。)
src:(可选)调用reduce的数组
initalValue:(可选)作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则使用数组中的第一个元素。 ps:在没有初始值的空数组上调用 reduce 将报错。
三、reduce如何运行
比如运行如下reduce代码:
[0, 1, 2, 3, 4].reduce(function(acc, cur, idx, arr) {
return acc + cur
})
callback被调用了四次,每次调用和返回值如下表:
callback | acc | cur | idx | arr | return value |
---|---|---|---|---|---|
1 call | 0 | 1 | 1 | [0, 1, 2, 3, 4] | 1 |
2 call | 1 | 2 | 2 | [0, 1, 2, 3, 4] | 3 |
3 call | 3 | 3 | 3 | [0, 1, 2, 3, 4] | 6 |
4 call | 6 | 4 | 4 | [0, 1, 2, 3, 4] | 10 |
如果为reduce()提供第二个参数,其运行结果如下:
[0, 1, 2, 3, 4].reduce(function(acc, cur, idx, arr) {
return acc + cur
}, 10)
callback | acc | cur | idx | arr | return value |
---|---|---|---|---|---|
1 call | 10 | 0 | 0 | [0, 1, 2, 3, 4] | 10 |
2 call | 10 | 1 | 1 | [0, 1, 2, 3, 4] | 11 |
3 call | 11 | 2 | 2 | [0, 1, 2, 3, 4] | 13 |
4 call | 13 | 3 | 3 | [0, 1, 2, 3, 4] | 16 |
5 call | 16 | 4 | 4 | [0, 1, 2, 3, 4] | 20 |
四、reduce与map和forEach的区别
- reduce() 方法将会对数组元素从左到右依次执行reducer函数,然后返回一个累计的值
- forEach() 方法对数组的每个元素执行一次给定的函数
- map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。
实现数组求和的例子:
// reduce 实现
var arr = [1, 2, 3, 4];
var sum = arr.reduce((acc, cur) => acc + cur);
// sum = 10
//forEach 实现
var sum = 0 ;
var arr = [1, 2, 3, 4];
arr.forEach(function(cur){
sum += cur;
})
// [1, 3, 6, 10]
// sum = 10
// map实现
var arr = [1, 2, 3, 4];
var sum = 0;
arr.map(function(cur) {
return sum += cur;
})
// return [1, 3, 6, 10]
// sum = 10
五、使用例子
按顺序执行Promise:
function run PromisebySeq(arr, input) {
return arr.reduce(
(promiseChain, curPromise) => promiseChain.then(curPromise) ,
Promise.resolve(input)
)
}
// promise function 1
function p1(a) {
return new Promise((resolve, reject) => {
resolve(a * 5);
});
}
// promise function 2
function p2(a) {
return new Promise((resolve, reject) => {
resolve(a * 2);
});
}
// function 3 - will be wrapped in a resolved promise by .then()
function f3(a) {
return a * 3;
}
// promise function 4
function p4(a) {
return new Promise((resolve, reject) => {
resolve(a * 4);
});
}
const promiseArr = [p1, p2, f3, p4];
runPromiseInSequence(promiseArr, 10)
.then(console.log);
六、Polyfill
if(!Array.prototype.reduce) {
Object.defineProperty(Array.prototype, 'reduce', {
value: function(callback) {
if(this === null) {
throw new TypeError('null can not call')
}
if(typeof callback !== 'function') {
throw new TypeError('callback is not a function')
}
var o = Object(this);
var len = o.length >>> 0;
var k = 0;
var value;
if(arguments.length >= 2) {
value = arguments[1]
} else {
while(k < len && !(k in o)) {
k++
}
if(k >= len) {
throw new TypeError('empt array')
}
value = o[k++];
}
while(k < len) {
if(k in o) {
value = callback(value, o[k], k, o);
}
k++
}
return value;
}
})
}