美文网首页js设计模式
柯里化和自动柯里化函数实现

柯里化和自动柯里化函数实现

作者: 瓯海 | 来源:发表于2021-09-14 11:12 被阅读0次

    柯里化定义

    维基百科定义

    • 是把接收多个参数的函数,变成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数,而且返回结果的新函数的技术
    • 柯里化声称 “如果你固定某些参数,你将得到接受余下参数的一个函数”
      简单讲就是将函数的多个参数返回不同的函数执行,将多个参数进行执行拆解成单步骤执行,一个函数执行一个步骤
      更简单的讲只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数
      举个例子
    function foo(a, b, c) {
      return a + b + c;
    }
    //柯里化处理之后的函数
    function sum(a) {
      return function (b) {
        return function (c) {
          return a + b + c;
        };
      };
    }
    console.log(foo(10, 20, 30));
    console.log(sum(10)(20)(30));
    

    foo函数接收三个函数,利用柯里化将三个参数返回相对应的函数去执行,每个函数执行一个对参数的操作
    可以将上面的柯里化处理函数简化

    const sum = (a) => (b) => (c) => a + b + c;
    

    但是在将上面的例子来看,进行柯里化之后的函数,步骤繁琐,执行效率也不高,但是为什么还要将函数进行柯里化呢,这里就涉及到设计模式相关的,有一个重要的模式就是让函数的职责单一

    • 当我们在进行函数式编程,每一个函数都尽可能只处理一类或者一个问题,而不是将所有的问题交给一个函数进行处理
    • 那么我们是否就可以将每次传入的参数在单一的函数中进行处理,处理完后在下一个函数中再使用处理后的结果
    function sum(a) {
      a = a + 2
      return function (b) {
         b = b * 2
        return function (c) {
           c = c ** 2
          return a + b + c;
        };
      };
    }
    

    柯里化还有一个重要的使用场景是对参数复用

    function log(date, type, message) {
      console.log(
        `[${date.getHours()}:${date.getMinutes()}]:[${type}]:[${message}]`
      );
    }
    log(new Date(), 'debug', '参数错误');
    log(new Date(), 'debug', 'not a function');
    log(new Date(), 'debug', 'bad request');
    

    以上面的例子来说,前两个参数是重复的,每次都要写同样的代码,唯一不同的是后面的message不同,如果有大量的日志需要重写,会非常麻烦,这时就可以用柯里化将参数复用

    const log = (date) => (type) => (message) => {
      console.log(
        `[${date.getHours()}:${date.getMinutes()}]:[${type}]:[${message}]`
      );
    };
    //时间重复
    const datelog = log(new Date());
    datelog('debug')('参数错误');
    datelog('request')('bad request');
    //时间和类型重复
    const dataAndType = log(new Date())('debug');
    dataAndType('参数错误');
    dataAndType('not a function');
    dataAndType('bad request');
    

    通过柯里化可以将重复的参数进行复用,减少了代码的冗余

    自动柯里化函数实现

    上面的柯里化函数都是手动实现的,接下来用一个函数来自动实现柯里化的过程

    function currying(fn) {
      //传入需要处理的函数
      function curryied(...args) {
        //传入处理函数的参数
        /**
         * 1.fn(10,20,30)
         * 2.fn(10)(20)(30)
         * 3.fn(10,20)(30)
         */
        //第一种情况
        //函数调用时参数全部使用
        if (args.length >= fn.length) {
          return fn.apply(this, args); //直接返回当前调用的函数,并且绑定当前调用函数的this
        } else {
          //第二种情况
          //第二种情况和第三种情况是一样的,这里是将第二种情况转换为第三种情况,在转换为第一种情况
          //递归调用
          //此时args是10,args2是20,
          //现在是需要将传递过来的参数进行拼接,直到转变成第一种情况
          function curryied2(...args2) {
            return curryied.apply(this, [...args, ...args2]);
          }
          return curryied2;
        }
      }
      return curryied;
    }
    
    function add(x, y, z) {
      return x + y + z;
    }
    
    var curryadd = currying(add);
    console.log(curryadd);
    console.log(curryadd(10)(20)(30));
    console.log(curryadd(10, 20, 30));
    console.log(curryadd(10, 20)(30));
    
    

    相关文章

      网友评论

        本文标题:柯里化和自动柯里化函数实现

        本文链接:https://www.haomeiwen.com/subject/nnxcgltx.html