zoukankan      html  css  js  c++  java
  • 柯里化函数的实现

    记录柯里化函数实现的学习过程:

    柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果。

    如果要实现下面这个方法:

    add(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)() // 133
    

    上面这个函数当参数为空的时候执行了内部参数所有值的相加,所以我们应该考虑当参数不为空的时候将缓存起来,在为空的时候再相加,这样的思路会用闭包的方式来实现。下面是实现方法:

    function add () {
      // 用来缓存所有的arguments值  
      let args = [].slice.call(arguments);
      // 新建currying函数实现柯里化  
      let currying = function () {
        // 如果参数为空,那么递归停止,返回执行结果
        if (arguments.length === 0) {
          return args.reduce((a, b) => a + b);
        } else {
          // 否则将参数保存到args里面,返回currying方法
          args.push(...arguments);
          return currying
        }      
      }
      return currying
    }
    add(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)() // 133

    上面有需要注意的一点,因为currying函数里面使用arguments,所以currying不能使用箭头函数,箭头函数内部的arguments的用法与箭头函数内部的this差不多,它取的是上一级函数的arguments值。如果想用箭头函数,currying函数可以这样改动:

      let currying = (...rest) => {
        // 如果参数为空,那么递归停止,返回执行结果
        if (rest.length === 0) {
          return args.reduce((a, b) => a + b);
        } else {
          // 否则将参数保存到args里面,返回currying方法
          args.push(...rest);
          return currying
        }      
      }

    我们返回的currying函数还可以使用callee来实现,原理相同,但是严格模式下不能使用:

    function add () {
      // 用来缓存所有的arguments值  
      let args = [].slice.call(arguments);
      // 新建currying函数实现柯里化  
      return function () {
        // 如果参数为空,那么递归停止,返回执行结果
        if (arguments.length === 0) {
          return args.reduce((a, b) => a + b);
        } else {
          // 否则将参数保存到args里面,返回currying方法
          args.push(...arguments);
          return arguments.callee
        }      
      }
    }
    add(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)() // 133

    对普通函数进行柯里化:

    // 柯里化函数的构造方法
    function curry (fn) {
      // 缓存除第一个参数的所有参数
      let args = [].slice.call(arguments, 1);  
      let _fn = function () {
        if (arguments.length === 0) {
          return fn.apply(this, args)
        } else {
          args.push(...arguments);
          return _fn
        }
      }
      return _fn
    }
    function add () {
      return [].reduce.call(arguments, (a, b) => a + b)
    }
    console.log(curry(add, 2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)()) // 133

    举例柯里化函数思想实现的场景:

    如减少重复传递的参数

    function simpleURL(protocol, domain, path) {
        return protocol + "://" + domain + "/" + path;
    }

    我们使用的时候将会这样:

    var myurl = simpleURL('http', 'mysite', 'home.html');
    var myurl2 = simpleURL('http', 'mysite', 'aboutme.html');

    我们可以用柯里化的思想改写:

    function curry (fn) {
      // 缓存除第一个参数的所有参数
      let args = [].slice.call(arguments, 1);  
      return function () {return fn.apply(this, args.concat(...arguments))
      }
    }
    
    
    // 避免每次调用重复传参
    let myURL1 = curry(simpleURL, 'https', 'mysite');
    let res1 = myURL1('home.html');    //
    
    console.log(res1);//https://mysite/home.html
    
    let myURL2 = curry(simpleURL, 'http', 'mysite');
    let res2 = myURL2('aboutme.html');    //
    
    console.log(res2);//http://mysite/aboutme.html
  • 相关阅读:
    14.9 InnoDB Row Storage and Row Formats InnoDB 行存储和行格式:
    14.8.3 Identifying the File Format in Use 确认使用的文件格式;
    14.8.2 Verifying File Format Compatibility 校验文件格式兼容性:
    14.8.2 Verifying File Format Compatibility 校验文件格式兼容性:
    14.8.1 Enabling File Formats
    14.6.7?Limits on InnoDB Tables InnoDB 表的限制
    第2章 PCI总线的桥与配置 分类: 浅谈PCI 2013-07-22 16:27 281人阅读 评论(0) 收藏
    1.5 PCI-X总线简介 分类: 浅谈PCI 2013-07-22 16:27 290人阅读 评论(0) 收藏
    1.4 PCI总线的中断机制 分类: 浅谈PCI 2013-07-22 16:27 313人阅读 评论(0) 收藏
    1.3 PCI总线的存储器读写总线事务 分类: 浅谈PCI 2013-07-22 16:26 261人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/kdcg/p/10192421.html
Copyright © 2011-2022 走看看