本节内容实际是函数式编程的进一步详细讲解,我们要对函数进行拆分潜逃调用离不开compose和pipe思想方法
compose函数指的是对要嵌套执行的函数进行平铺,嵌套执行指的是一个函数的返回结果作为另一个函数的执行参数。核心思想是专注于函数执行过程,隔离数据的影响。
概念看起来太难懂,我们直接上例子:有这样一个需求 求一个数的10倍再加1的值
完全命令式编程实现:
let calculate = x=>x*10+1;
console.log(calculate(1))//11
函数式编程实现该需求 ,我们就需要两个过程的计算 10倍,加1
let add = (a)=>{
return a+1;
}
let multiple = (b)=>{
return b*10;
}
console.log(add(multiple(1)))
11
我们用compose方法将上面的函数调用add(multiple(1))
改造下
let add = (a)=>{
return a+1;
}
let multiple = (b)=>{
return b*10;
}
// console.log(add(multiple(1)))
let compose = (f,g)=>{
return function (x){
return f(g(x));
}
}
let calculate = compose(add,multiple);
console.log(calculate(1));
11
我们用compose方法对两个方法进行了平铺组合,但他不具备通用性,再次改造:
let add = (a)=>{
return a+1;
}
let multiple = (b)=>{
return b*10;
}
let compose = function(){
let args = [].slice.call(arguments);
return function (x){
return args.reduceRight(function(res,cb){
return cb(res);
},x)
}
}
let calculate = compose(add,multiple);
console.log(calculate(1));
11
注意运算结果是从右向左执行,所以compose中的参数顺序(add,multiple)先乘后加,同时我们要用到数组的reduceRight方法,同理如果我们改变为从左向右执行:
let add = (a)=>{
return a+1;
}
let multiple = (b)=>{
return b*10;
}
let compose = function(){
let args = [].slice.call(arguments);
return function (x){
return args.reduce(function(res,cb){
return cb(res);
},x)
}
}
let calculate = compose(multiple,add);
console.log(calculate(1));
仅仅修改args.reduce
方法和compose(multiple,add)
参数顺序即可。
我们将上面的方法用es6实现
let add = (a)=>{
return a+1;
}
let multiple = (b)=>{
return b*10;
}
const compose = (...args)=>x=>args.reduce((res,bc)=>bc(res),x);
let calculate = compose(multiple,add);
console.log(calculate(1));
11
看不懂了吧,所谓的高大上就是这么来的。
compose函数是从右向左去实现的数据执行流,而从左向右的数据执行流就是pipe函数了(通一个第二个你自然也就会了)
需要说明的现在前端工具webpack 中loader 的执行顺序就是compose方法实现的。
新建pipe.js
/**
* pipe Function from left to right
* pipe(a,b,c) = (...args) => c(b(a(...args)));
*
* 代数计算, 符合阅读习惯, 从左到右.
*
* 请实现一个pipe函数,并且保证pipe.test.js通过
*
* @param {Array[Function]} funcs
*/
const pipe =function () {
let args = [].slice.call(arguments);
return function (x) {
return args.reduce(function (res, cb) {
return cb(res);
}, x)
}
}
module.exports = {pipe};
新建测试文件 pipe.test.js
const { pipe } = require("./pipe")
let add = n => n + 3;
let multiple = n => n * 2;
let minus = n => n - 1;
test("pipe()(10) equals ", () => {
expect(pipe()(10)).toBe(10);
});
test("pipe(add)(10) equals ", () => {
expect(pipe(add)(10)).toBe(13);
});
test("pipe(add, multiple, minus)(10) equals ", () => {
expect(
pipe(
add,
multiple,
minus
)(10)
).toBe(25);
});
test("pipe(multiple, add, minus)(10) equals ", () => {
expect(
pipe(
multiple,
add,
minus
)(10)
).toBe(22);
});
test("pipe(minus, add, multiple)(10) equals ", () => {
expect(
pipe(
minus,
add,
multiple
)(10)
).toBe(24);
});
执行测试 npm run test 结果:
如果您对jest测试还不够熟悉请移步我的上篇“js高级进阶之单元测试jest”
保证你半小时学会jest,而且还会了compose与pipe,别忘记点赞哦!