前言
在《重构》这本书里,提到了一个重构的方法“以管道取代循环”,那么什么是管道呢?reduce是如何工作的?
Array.reduce(callback[, initialValue])
reduce(归纳),为数组中的每一个元素执行callback方法,并将每次callback方法的返回结果,作为下一次调用callback方法的参数 (通常也把这种思想叫做管道机制pipeline) 通常应用于求和、计算数组的平均值、返回一个数组、也可以将嵌套数组扁平化为一个数组、处理一系列函数。
callback方法接收4个参数
- Accumulator (acc) (累计器)
- Current Value (cur) (当前值)
- Current Index (idx) (当前索引 可选)
- Source Array (src) (源数组 可选)
initialValue (初始值 可选)
作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。在没有初始值的空数组上调用 reduce 将报错。初始值为空数组输出结果为数组。
求和
1
2
3
4
5
6
7
const array1 = [1, 2, 3, 4];
const reducer = (acc, cur) => acc + cur;
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer)); //10
// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5)); //15
一串字符串中每个字母出现的次数
1
2
3
4
5
var arrString = 'abcdaabc';
const count = arrString.split('').reduce((acc,cur)=>{
acc[cur]=(acc[cur]||0)+1
return acc
},{})
数组去重
1
2
3
4
5
6
7
8
let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4];
let result = arr.sort().reduce((init,cur)=>{
if(init.length==0||init[init.length-1]!=cur) {
init.push(cur)
}
return init
},[])
console.log(result);
嵌套数组扁平化
1
2
3
4
5
const data = [[2,3,4,5],[6,7,8,9],[11,22,33,44]];
const flat = data.reduce((total,amount)=>{
return total.concat(amount);
},[]);
console.log(flat);
歪个楼,另一种扁平化的方式,是ES10新特性flat,本质上就是归纳(reduce)。 flat()方法最基本的作用是数组降维,除此之外,还可以利用flat()方法的特性来去除数组的空项。
1
2
3
4
5
6
7
8
9
var arr1 = [1, 2, [3, 4, [5, 6]]];
arr1.flat(); // [1, 2, 3, 4, [5, 6]]
//展开任意深度的嵌套数组
arr1.flat(Infinity); // [1, 2, 3, 4, 5, 6]
var arr2 = [1, 2, , 4, 5];
arr2.flat();
// [1, 2, 4, 5]
按顺序运行Promise
reduce一个比较强大的功能是可以处理函数,用for of没办法遍历一系列函数,但是reduce可以。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function runPromiseInSequence(arr, input) {
return arr.reduce(
(promiseChain, currentFunction) => promiseChain.then(currentFunction),
Promise.resolve(input)
);
}
function p1(a) {
return new Promise((resolve, reject) => {
resolve(a * 5);
});
}
function p2(a) {
return new Promise((resolve, reject) => {
resolve(a * 2);
});
}
function f3(a) {
return a + 1;
}
function p4(a) {
return new Promise((resolve, reject) => {
resolve(a * 4);
});
}
const promiseArr = [p1, p2, f3, p4];
runPromiseInSequence(promiseArr, 10)
.then(console.log); // 404
管道
管道是一系列函数把一个初始值转化为最终值的过程。假设有一个函数集合,这些函数可以允许我们增加,减少,相乘,折半某一个数字。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function add(val) {
return val + 1
}
function cut(val) {
return val - 1
}
function double(val) {
return val * 2
}
function half(val) {
return val / 2
}
如果要计算((val+1)*2-1)/2
可以利用reduce函数创造一个管道来解决
1
2
3
4
5
//计算((val+1)*2-1)/2
const result = [add, double, cut, half].reduce((total, fn) => {
return fn(total)
}, 2)
console.log(result);//2.5