zoukankan      html  css  js  c++  java
  • 关于js的高级函数(惰性函数,函数柯里化,级联函数)

    《1》首先是惰性函数

    惰性载入表示函数执行的分支只会在函数第一次掉用的时候执行,在第一次调用过程中,该函数会被覆盖为另一个按照合适方式执行的函数,这样任何对原函数的调用就不用再经过执行的分支了。

    看下面典型的例子:

    为了兼容各浏览器,对事件监听的的支持:

    function addEvent (type, element, fun) {
        if (element.addEventListener) {
            element.addEventListener(type, fun, false);
        }
        else if(element.attachEvent){
            element.attachEvent('on' + type, fun);
        }
        else{
            element['on' + type] = fun;
        }
    }

    上面是注册函数监听的各浏览器兼容函数。由于,各浏览之间的差异,不得不在用的时候做能力检测。显然,单从功能上讲,已经做到了兼容各浏览器。但是,每次绑定监听,都会对能力做一次检测,这就没有必要了,真正的应用中,这显然是多余的,同一个应用环境中,只需要检测一次即可。

    于是有了如下改变:

    function addEvent (type, element, fun) {
        if (element.addEventListener) {
            addEvent = function (type, element, fun) {
                element.addEventListener(type, fun, false);
            }
        }
        else if(element.attachEvent){
            addEvent = function (type, element, fun) {
                element.attachEvent('on' + type, fun);
            }
        }
        else{
            addEvent = function (type, element, fun) {
                element['on' + type] = fun;
            }
        }
        return addEvent(type, element, fun);
    }

    可以看出,第一次调用addEvent会对浏览器做能力检测,然后,重写了addEvent。下次再调用的时候,由于函数被重写,不会再做能力检测。

    类似的例子还有:XMLHttRequest:

    function createXHR() {
     4     var xhr;
     5     try{
     6         xhr = new XMLHttpRequest();
     7     }catch(e) {
     8         handleErr(e);
     9 
    10         try {
    11             xhr = new ActiveXObject("Msxml2.XMLHTTP");
    12         }catch(e) {
    13             try{
    14                 xhr = new ActiveXObject("Microsoft.XMLHTTP");
    15             }catch(e) {
    16                 xhr = null;
    17             }
    18         }
    19     }
    20 
    21     return xhr ;
    22 }
    23 
    24 function handleErr(error) {
    25     // 这一步在实战中很重要,因为catch会延长作用域链,所以是在全局作用域声明的e
    26     // 这里我们把它赋给局部变量,则查找更快
    27     var err = error;
    28 
    29     // do sth.
    30 }

    由于不同的浏览器的xmlhttpreque对象的不同形式,为了兼容同样要在使用ajax时判断,但同样这样的判断只需一次。

    看惰性函数优化后:

    function createXHR() {
     5     var xhr;
     6     if(typeof XMLHttpRequest != 'undefined') {
     7         xhr = new XMLHttpRequest();
     8         createXHR = function() {
     9             return new XMLHttpRequest();
    10         }
    11     }else {
    12         try {
    13             xhr = new ActiveXObject("Msxml2.XMLHTTP");
    14             createXHR = function() {
    15                 return new ActiveXObject("Msxml2.XMLHTTP");
    16             }
    17         }catch(e) {
    18             try {
    19                 xhr = new ActiveXObject("Microsoft.XMLHTTP");
    20                 createXHR = function() {
    21                     return new ActiveXObject("Microsoft.XMLHTTP");
    22                 }
    23             }catch(e) {
    24                 createXHR = function () {
    25                     return null;
    26                 }
    27             }
    28         }
    29     }
    30     return xhr 
    31 }

    代码中,我们让函数在第一次运行之后,则判断除了浏览器的环境,就被重新赋值了。
    赋值后的函数是直接return 对应的方法。所以,这个函数,需要第二次调用的时候才真正的被调用。
    正是因为它第二次调用函数的时候,没有去走第一次调用那样复杂的判断的路,所以显得“懒惰”。因此我们叫它 惰性函数

    可以总结出在哪些情况下使用惰性函数:

    1 应用频繁,如果只用一次,是体现不出它的优点出来的,用的次数越多,越能体现这种模式的优势所在;

    
    

    2 固定不变,一次判定,在固定的应用环境中不会发生改变;

    《2》函数柯里化

    关于这个看了好多资料,其实还是并没有很懂,<摊手>

    直接上代码:

    // //函数柯里化

    1》提高适用性:

    【通用函数】解决了兼容性问题,但同时也会再来,使用的不便利性,不同的应用场景往,要传递很多参数,以达到解决特定问题的目的。有时候应用中,同一种规则可能会反复使用,这就可能会造成代码的重复性。

    function square(i) {
        return i * i;
    }

    function dubble(i) {
        return i *= 2;
    }

    function map(handeler, list) {
        return list.map(handeler);
    }

    // 数组的每一项平方
    map(square, [1, 2, 3, 4, 5]);
    map(square, [6, 7, 8, 9, 10]);
    map(square, [10, 20, 30, 40, 50]);
    // ......

    // 数组的每一项加倍
    map(dubble, [1, 2, 3, 4, 5]);
    map(dubble, [6, 7, 8, 9, 10]);
    map(dubble, [10, 20, 30, 40, 50]);

    函数柯里化改造后:

    function curry(fn){
     var args=Array.prototype.slice.call(arguments,1);
     console.log(args);//输出:function aquare(){...}
     return function(){
      var innerArgs=Array.prototype.slice.call(arguments);
      console.log(innerArgs);//输出:1,2,3,4,5
      var finalArgs=args.concat(innerArgs);
      console.log(finalArgs);//输出:function square(){},1,2,3,4,5
      return  fn.apply(null,finalArgs);
     }
    }

    function square(i) {     return i * i; }

    function dubble(i) {     return i *= 2; }

    function map(handeler, list) {     return list.map(handeler); }

    var mapSQ = curry(map, square);

    mapSQ([1, 2, 3, 4, 5]);

    mapSQ([3,2,5,7,6,7]);

    var mapDB = curry(map, dubble);

    mapDB([1, 2, 3, 4, 5]);

    mapDB([2,5,7,6,2,3]);

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

    var currying = function (fn) {
        var _args = [];
        return function () {
            if (arguments.length === 0) {
                return fn.apply(this, _args);
            }
            Array.prototype.push.apply(_args, [].slice.call(arguments));
            return arguments.callee;
        }
    };

    var multi=function () {
        var total = 0;
        for (var i = 0, c; c = arguments[i++];) {
            total += c;
        }
        return total;
    };

    var sum = currying(multi); 
     
    sum(100,200)(300);
    sum(400);
    console.log(sum());     // 1000  (空白调用时才真正计算)

    上面的代码其实是一个高阶函数(high-order function), 高阶函数是指操作函数的函数,它接收一个或者多个函数作为参数,并返回一个新函数。此外,还依赖与闭包的特性,来保存中间过程中输入的参数。即:

    • 函数可以作为参数传递
    • 函数能够作为函数的返回值
    • 闭包

    柯里化的作用

    • 延迟计算。上面的例子已经比较好低说明了。
    • 参数复用。当在多次调用同一个函数,并且传递的参数绝大多数是相同的,那么该函数可能是一个很好的柯里化候选。
    • 动态创建函数。这可以是在部分计算出结果后,在此基础上动态生成新的函数处理后面的业务,这样省略了重复计算。或者可以通过将要传入调用函数的参数子集,部分应用到函数中,从而动态创造出一个新函数,这个新函数保存了重复传入的参数(以后不必每次都传)。例如,事件浏览器添加事件的辅助方法:

    var addEvent = function(el, type, fn, capture) {
         if (window.addEventListener) {
             el.addEventListener(type, function(e) {
                 fn.call(el, e);
             }, capture);
         } else if (window.attachEvent) {
             el.attachEvent("on" + type, function(e) {
                 fn.call(el, e);
             });
         }
    };

    每次添加事件处理都要执行一遍 if...else...,其实在一个浏览器中只要一次判定就可以了,把根据一次判定之后的结果动态生成新的函数,以后就不必重新计算。

    var addEvent = (function(){
        if (window.addEventListener) {
            return function(el, sType, fn, capture) {
                el.addEventListener(sType, function(e) {
                    fn.call(el, e);
                }, (capture));
            };
        } else if (window.attachEvent) {
            return function(el, sType, fn, capture) {
                el.attachEvent("on" + sType, function(e) {
                    fn.call(el, e);
                });
            };
        }
    })();

    《3》级联函数

    !--JavaScript级联函数-->
    <!--本课时介绍JavaScript级联函数,
    级联函数也叫链式函数,方法链一
    般适合对一个对象进行连续操作
    (集中在一句代码)。一定程度上
    可以减少代码量,缺点是它占用了
    函数的返回值。-->
    

    function myclassA(){
     this.name="";
     this.age="";
     this.sex="";
    }
    myclassA.prototype={
     setname:function(){
      this.name="katherine";
      return this;
     },
     setage:function(){
      this.age="22";
      return this;
     },
     setsex:function(){
      this.sex='girl';
      return this;
     }
    }
    var me =new myclassA();
    console.log(me.setname().setage().setsex());

    // myclassA {name: "katherine", age: "22", sex: "girl"}

    参考自http://www.tuicool.com/articles/N7Z3qey,

    参考:

    http://sombie.diandian.com/post/2013-06-28/40050585369

    http://book.2cto.com/201211/9320.html

    http://zh.wikipedia.org/wiki/Currying

    http://www.ibm.com/developerworks/cn/web/1006_qiujt_jsfunctional/

    http://www.cnblogs.com/lwbqqyumidi/archive/2012/12/03/2799833.html

    纯属个人学习参考资料

    
    
    
  • 相关阅读:
    alertify、js、css 使用简介
    html 跳转页面,同时跳转到一个指定的位置
    java 解析 json 遍历未知key
    JSON 字符串 与 java 对象的转换
    iOS安全系列之 HTTPS 进阶
    iOS安全系列之 HTTPS
    iOS-socket
    他人整理开源组件列表
    iOS Layout机制相关方法
    在写一个iOS应用之前必须做的7件事(附相关资源)
  • 原文地址:https://www.cnblogs.com/xiaoai-tang/p/6561740.html
Copyright © 2011-2022 走看看