zoukankan      html  css  js  c++  java
  • 【函数】compose 函数和 pipe 函数

    目录:

    1、compose 函数

    2、pipe 函数

    compose 函数

      compose 函数将需要嵌套执行的函数平铺。嵌套执行指的是,一个函数的返回值作为另一个函数的参数。

      其实 compose 函数在函数式编程中通常用来将几个有特点的函数拼凑在一起,让他们结合,产生一个崭新的函数。compose 函数的作用是实现函数式编程的 Pointfree, 使我们专注于转换而不是数据。也就是说,我们完全可以把数据处理的过程定义成一种与参数无关的合成运算,不需要用到代表数据的那个参数,只要把一些简单的运算步骤合成在一起即可,而 Pointfree 指的是不使用所要处理的值,只合成运算过程,即我们所指的无参数分隔。

      现在有这么一个需求,计算一个数,加上 10,再乘以 10的值。可能有人会这么做:

    1 let calculate = x => ( x + 10 ) *10;
    2 console.log( calculate( 10 ) );     //输出:200

      上面,这样写是没有问题的,但是这是命令式编程,这样的代码完全不具备复用性。作为一个函数式开发者,会对这段代码进行抽象来实现简化代码的目的,而且,函数式编程就是将程序分解为一些更可重用、更可靠、更易于理解的部分,然后再将它们组合起来形成一个更易于推理的程序整体。

      以上面的需求为例,我们关注的是它的动作,先加上 10, 再乘以 10。可以像下面这样做:

    1 let add = x => x + 10;
    2 let multiply = y => y * 10;
    3 console.log( multiply(add(10)) );   //输出:200

      上面,将 add 函数的执行结果作为 multiply 的参数,这样也能实现需求。但是根据复合函数的定义,需要将代表两个动作的函数合成一个函数。分析 2 个函数的特性,第一,是两个函数都有一个共同的参数,第二,是函数的执行的顺序是从右到左,第三,是前面函数的结果将由后面的函数处理,根据特性,可以这样实现:

    1 let add = x => x + 10;
    2 let multiply = y => y * 10;
    3 let compose = (f, g) => {
    4     return function(x){
    5         return f(g(x));
    6     }
    7 }
    8 let calculate = compose( multiply, add );
    9 console.log( calculate(10) );   //输出:200

      上面,使用了闭包来实现。首先,定义一个 compose 函数,接收 2 个函数作为参数。这个 compose 函数返回一个匿名函数,这个匿名函数接收 1 个参数,而且这个匿名函数将 2 个函数执行的结果返回。当调用的时候,只需要将 2 个函数作为参数传入。注意,根据函数调用的顺序,这里的执行动作是从右往左,即先执行 add ,再执行 multiply。

      这样的 compose 函数没有通用性,因为它只可以处理 2 个函数,接下来实现通用的 compose 函数:

     1 let add = x => x + 10;
     2 let multiply = y => y * 10;
     3 let compose = function(){
     4     let args = [].slice.call( arguments );
     5     return function( x ){
     6         return args.reduceRight( function (res, cb) {
     7             return cb(res);
     8         }, x)
     9     }
    10 }
    11 let calculate = compose( multiply, add );
    12 console.log( calculate(10) );   //输出:200

      上面,通用的 compose 函数要做的第一件事是将传入的函数作为参数收集起来,所以这里将 arguments 转换为数组,因为需要把上一次执行结果当作参数传给下一次执行,所以可以使用 reduce() 来实现,reduce方法可以接收一个函数作为累加器,也就是说 reduce() 会将数组中的每一个元素依次执行传入的函数。同时要注意,复合函数执行的顺序是自右向左依次执行,而 reduce() 是从左往右开始累加,reduceRight() 是从右往左开始累加,所以这里用 reduceRight()。调用 compose 函数的执行顺序依然是从右往左执行。

      可以使用更简洁的 es6 语法实现 compose 函数,如下:

    1 let add = x => x + 10;
    2 let multiply = y => y * 10;
    3 //es6 写法
    4 const compose = (...args) => x => args.reduceRight( (res, cb ) => cb(res), x);
    5 let calculate = compose( multiply, add );
    6 console.log( calculate(10) );   //输出:200

      其实原理都是将传入的函数收集,唯一要注意的是:compose 执行方向是从右往左执行,所以要使用 reduceRight() 。通过 compose,在开发中可以去设计和抽象功能到具体的函数里面,以便后期的复用。而且更多的时候,compose 函数的存在其实是服务中间件的,redux 中间件就是通过 compose 来实现的。webpack loader 的加载顺序也是从右往左的,这是因为 webpack 选择了 compose 方式去实现。

    pipe 函数

       compose 和 pipe 都是函数组合,组合是函数式编程非常重要的思想,其实,就是将多个函数组合在一起,以便能够构建出一个新函数。在函数式编程中,纯函数应该被设计为只做一件事,如果想实现多个功能,可以通过函数的组合来实现。

      pipe 函数是 compose 函数的复制品,唯一修改的是数据流方向,pipe 函数和 compose 函数做的事情相同,只不过交换了数据流方向,也就是说,compose 函数数据流的方向是从右向左,最右侧的函数会首先执行,之后数据传递给下一个函数,以此类推,一直到最左侧的函数最后执行。而 pipe 函数正好相反。

  • 相关阅读:
    MongoDB
    新公司管理经营
    剪辑理论
    色彩理论
    商业模式
    电影手法
    [好文转载] 每个程序员都应该学习使用Python或Ruby
    File类递归
    【CF1447】div2复盘
    【心得体会】11.9-11.15
  • 原文地址:https://www.cnblogs.com/xiaoxuStudy/p/12602865.html
Copyright © 2011-2022 走看看