zoukankan      html  css  js  c++  java
  • javascript的currying函数

    curring的概念将函数式编程的概念和默认参数以及可变参数结合在一起.一个带n个参数,curried的函数固化第一个参数为固定参数,并返回另一个带n-1个参数的函数对象,分别类似于LISP的原始函数car和cdr的行为。currying能泛化为偏函数应用(partial function application, PFA),p 这种函数将任意数量(顺序)的参数的函数转化为另一个带剩余参数的函数对象。

    最早期的curry函数有点多态的意味,就是根据函数参数在内部选用分支:

    //http://www.openlaszlo.org/pipermail/laszlo-user/2005-March/000350.html
    // ★★On 8 Mar 2005, at 00:06, Steve Albin wrote:
          function add(a, b) {
            if (arguments.length < 1) {
              return add;
            } else if (arguments.length < 2) {
              return function(c) { return a + c }
            } else {
              return a + b;
            }
          }
    
          var myadd = add( 2 );
          var total = myadd(3);
    

    日本的一个先行者可能在未搞清arguments也能用Array的原生方法转换为数组的时候,用非常复杂的正则与eval搞出一个更接近现代currying意味的函数。

          function curry(fun) {
            if (typeof fun != 'function') {
              throw new Error("The argument must be a function.");
            }
            if (fun.arity == 0) {
              throw new Error("The function must have more than one argument.");
            }
    
            var funText = fun.toString();
            var args = /function .*\((.*)\)(.*)/.exec(funText)[1].split(', ');
            var firstArg = args.shift();
            var restArgs = args.join(', ');
            var body = funText.replace(/function .*\(.*\) /, "");
    
            var curriedText =
              "function (" + firstArg + ") {" +
              "return function (" + restArgs + ")" + body +
              "}";
    
            eval("var curried =" + curriedText);
            return curried;
          }
    

    接着是闭包的流行,与数组转换arguments的技术的发现,现代currying函数终于粉墨登场,就好像15~17世纪大航海时代的地理大发现,javascript的世界突然间开阔了许多。

    //一个简单的现代currying函数
    function curry (fn, scope) {
        var scope = scope || window;
        var args = [];
        for (var i=2, len = arguments.length; i < len; ++i) {
            args.push(arguments[i]);
        };
        return function() {
    	    fn.apply(scope, args);
        };
    }
    

    一般的currying函数只有两重,执行情况如下,第一次执行参数不足返回内部函数,第二次执行才最终完成。不过针对这参数,我们还是可以做一些文章。看如下函数:

    function sum(){
        var result=0;
        for(var i=0, n=arguments.length; i<n; i++){
            result += arguments[i];
        }
        return result;
    }
    alert(sum(1,2,3,4,5)); // 15
    

    这就没有所谓的参数不足问题,传入一个参数,它也计算。但不传入参数呢?无错,区别在于有没有参数。我们可以让它不断执行自身,如果参数存在的情况下。最后在没有参数的情况下,一次过执行。换言之,前面的步骤是用于储存参数。

    var sum2= curry(sum);
        sum2= sum2(1)(2)(3)(4)(5);
    
    sum2(); // 15
    

    比起一般的currying函数,这有点难度。具体看注解:

          var curry= function(fn){//原函数的参数为函数
            return function(args){//内部函数的参数为数组,由于立即执行,因此直接到第三重去
              //args是相对于第三重内部函数可是全局变量
              var self= arguments.callee;//把自身保存起来(就是那个数组为参数的第二重函数)
              return function(){ //这才是第二次调用的函数
                if(arguments.length){//如果还有要添加的参数
                  [].push.apply(args,arguments);//apply把当前传入的所有参数放进args中
                  return self(args);
                }else{
                  return fn.apply(this,args);//apply的第二参数为数组
                }
              }
            }([]);
          };
    

    或者每次传入多个参数:

    但上面的函数有不足之处,最后怎么也要放个括号,我们想只要参数足够就返回结果,多出的参数忽略。改进如下:

     
         function curry(f) {
            if (f.length == 0) return f;
            function iterate(args) {
              if (args.length <= f.length)
                return f.apply(null, args);
              return function () {
                return iterate(args.concat(Array.prototype.slice.call(arguments)));
              };
            }
            return iterate([]);
          }
    

  • 相关阅读:
    CentOS7安装node环境
    【异常】update更新java.sql.SQLException: Duplicate entry '2019-07-30 00:00:00-110100' for key
    MySQL查询多行重复数据SQL
    Phoenix批量提交优化,官网的demo
    (转) 读懂IL
    Docker
    Docker
    Rest之路
    (转)Docker
    Docker
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/1598761.html
Copyright © 2011-2022 走看看