偶然间看到了一段代码
const pipeline = (...focus) => val => focus.reduce((a, b) => b(a), val);
const plus1 = a => a + 1;
const mult2 = a => a * 2;
const addThenMult = pipeline(plus1, mult2);
addTheMult(5);
// 12
是一段关于管道机制的代码实现,由于第一眼看到时并没有like反应过来代码的作用,所以就拿出来研究了一下,这段代码究竟起到什么作用,继续看下去
首先先来复习一下reduce函数,它是Array原型上的一个方法,MDN对其描述为
reduce()
方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
其语法为
const arr = []
arr.reduce(callback(accumulator, currentValue, index, array), initValue)
- callback:回调函数,将对数组的每一项执行回调
- accumulator:累加器,与累计结果,遍历结束之后作为返回值返回
- currentValue:当前值
- index(可选):当前值的索引
- array(可选):进行遍历的整个数组
- initValue(可选):初始值,如果没有传值初始值就以数组的第一项作为起始值
例如,最简单🍳的用法,计算一个数组中所有项的和
const numArr = [1, 2, 3, 4, 5, 6]
const sum = numArr.reduce((acc, cur) => acc + cur)
// sum: 21
揭秘时刻
开头的代码的实际效果是这样的,将第一个函数的返回值作为第二个函数的参数
const plus1 = a => a + 1;
const mult2 = a => a * 2;
mult2(plus1(5));
// 12
两种写法区别在于通过工厂的形式可以在更多个函数嵌套操作时可以清晰一点
到底是怎么实现这种效果的呢?继续看
const pipeline = (...focus) => val => focus.reduce((a, b) => b(a), val);
首先这段代码的返回值是一个函数,该函数接收一个参数,并将该参数作为初始值进行操作。第一轮操作开始的时候reduce的回调函数接收到的参数分别是a->val、b->focus[0]
const plus1 = a => a + 1;
const mult2 = a => a * 2;
const addThenMult = pipeline(plus1, mult2);
addTheMult(5);
再来看这里,focus就是这两个函数,那么focus[0]即第一轮的b就是plus1函数、a就是5,所以第一轮执行的操作是b(a)也就是plus1(5)结;然后进入第二轮,此时刚才的到的结果会变成a,b变成了focus[1],这一轮的操作就是**mult(plus(5))**,这也就得到了我们刚才说的效果
不得不说这个API是真的秀👍🏻,之前我一直以为reduce的作用就是简单的用于合并数组,现在我对它的看法已经发生了“微妙的变化”。
然后我查了一下reduce的其他“骚操作”,大致如下几类
找出最大/小值
let arr = [23,123,342,12];
let max = arr.reduce((pre,cur,index,arr) => {
return pre > cur ? pre : cur
});
字符统计
let str = 'abcdaabc';
str.split('').reduce((res, cur) => {
res[cur] ? res[cur] ++ : res[cur] = 1
// 如果cur第一次出现,记为1,否则记录数+1
return res;
}, {})
数组去重
let arr = [1, 2, 3, 4, 4, 1]
let newArr = arr.reduce((pre,cur) => {
if(!pre.includes(cur)){
return pre.concat(cur)
}else{
return pre
}
},[]
数组扁平化
let arr = [[0, 1], [2, 3], [4, 5]]
let newArr = arr.reduce((pre,cur) => {
return pre.concat(cur)
},[])