js高级进阶之compose函数和pipe函数

本节内容实际是函数式编程的进一步详细讲解,我们要对函数进行拆分潜逃调用离不开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函数并用jest测试

新建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,别忘记点赞哦!

发布了69 篇原创文章 · 获赞 6 · 访问量 1877

猜你喜欢

转载自blog.csdn.net/weixin_40073115/article/details/103842925
今日推荐