JS立即执行函数

参考:

http://www.zhihu.com/question/35832285

http://www.cnblogs.com/pigtail/p/3442463.html

http://www.ayqy.net/blog/js%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B011_%E9%AB%98%E7%BA%A7%E6%8A%80%E5%B7%A7/


整理:

立即执行函数的两点作用,分别是隔离作用域和实现惰性载入。

隔离作用域,由于js不支持块级作用域,通过函数来进行模拟。

var currTime = (function(){
    var time = new Date()

    var year  = time.getFullYear()
    var month = time.getMonth()
    var date  = time.getDate()
    var hour  = time.getHours()
    var min   = time.getMinutes()
    var sec   = time.getSeconds()

    return year + '/' + month + '/' + date + ' ' + hour + ':' + min + ':' + sec
})()
内部定义的变量不会影响到外部,实现作用域隔离。


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

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;
    }
}
复制代码

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

下面我们重写上面的addEvent:

复制代码
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。下次再调用的时候,由于函数被重写,不会再做能力检测。

同样的应用,javascript高级程序设计里的一例子:

复制代码
function createXHR(){
    if (typeof XMLHttpRequest != "undefined"){
        return new XMLHttpRequest();
    } else if (typeof ActiveXObject != "undefined"){
        if (typeof arguments.callee.activeXString != "string"){
            var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
                            "MSXML2.XMLHttp"];
    
            for (var i=0,len=versions.length; i < len; i++){
                try {
                    var xhr = new ActiveXObject(versions[i]);
                    arguments.callee.activeXString = versions[i];
                    return xhr;
                } catch (ex){
                    //skip
                }
            }
        }
    
        return new ActiveXObject(arguments.callee.activeXString);
    } else {
        throw new Error("No XHR object available.");
    }
}
复制代码

很显然,惰性函数在这里优势更加明显,因为这里有更多的分支。下面我们看一下重写后台的函数:

复制代码
function createXHR() {
            if (typeof XMLHttpRequest != "undefined") {
                createXHR = function () {
                    return new XMLHttpRequest();
                }
                return new XMLHttpRequest();
            } else if (typeof ActiveXObject != "undefined") {
                var curxhr;
                var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
                    "MSXML2.XMLHttp"];

                for (var i = 0, len = versions.length; i < len; i++) {
                    try {
                        var xhr = new ActiveXObject(versions[i]);
                        curxhr = versions[i];
                        createXHR = function () {
                            return new ActiveXObject(curxhr);
                        }
                        return xhr;
                    } catch (ex) {
                        //skip
                    }
                }
            } else {
                throw new Error("No XHR object available.");
            }
        }
复制代码

 

浏览器之间最大的差异,莫过于Dom操作,Dom操作也是前端应用 中最频繁的操作,前端的大多性能提升,均体现在Dom操作方面。下面看一个Dom操作方面的惰性函数定义例子:

复制代码
var getScrollY = function() {

    if (typeof window.pageYOffset == 'number') {

        getScrollY = function() {
            return window.pageYOffset;
        };

    } else if ((typeof document.compatMode == 'string') &&
               (document.compatMode.indexOf('CSS') >= 0) &&
               (document.documentElement) &&
               (typeof document.documentElement.scrollTop == 'number')) {

        getScrollY = function() {
            return document.documentElement.scrollTop;
        };

    } else if ((document.body) &&
               (typeof document.body.scrollTop == 'number')) {

      getScrollY = function() {
          return document.body.scrollTop;
      }

    } else {

      getScrollY = function() {
          return NaN;
      };

    }

    return getScrollY();
}
复制代码

 惰性函数定义应用还体现在创建单例上:

复制代码
function Universe() {

    // 缓存的实例
    var instance = this;

    // 其它内容
    this.start_time = 0;
    this.bang = "Big";

    // 重写构造函数
    Universe = function () {
        return instance;
    };
}
复制代码

当然,像上面这种例子有很多。惰性函数定义,应用场景我们可以总结一下:

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

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

3 复杂的分支判断,没有差异性,不需要应用这种模式;


  1. 在第一次执行分支检测时,覆盖原有函数,例如:

    function detect(){
      if(...){
        detect = function(){
          //
        }
      }
      else if(...){
        detect = function(){
          //
        }
      }
      else...
    }
    
  2. 可以用匿名函数立即执行并返回匿名函数来实现惰性载入,例如:

    var detect = (function(){
      if(...){
        return function(){
          //
        }
      }
      else if(...){
        return function(){
          //
        }
      }
      else...
    })();
    

第一种方式第一次调用时损失性能,以后调用不会损失性能;第二种方式在第一次调用时也不会损失性能,因为把时耗放到了第一次载入代码时



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值