前端開發者進階之惰性函數定義


穆乙:http://www.cnblogs.com/pigtail/p/3447660.html 

函數是js世界的一等公民,js的動態性、易變性在函數的應用上,體現的淋漓盡致。做為參數,做為返回值等,正是函數這些特性,使得js開發變的有趣。

下面就闡述一下,js一個有趣的應用--惰性函數定義(Lazy Function Definition)。

惰性載入表示函數執行的分支只會在函數第一次掉用的時候執行,在第一次調用過程中,該函數會被覆蓋為另一個按照合適方式執行的函數,這樣任何對原函數的調用就不用再經過執行的分支了。

下面我們看幾個典型的例子:

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();
}

 惰性函數定義應用還體現在創建單例上:

unction Universe() {

    // 緩存的實例
    var instance = this;

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

    // 重寫構造函數
    Universe = function () {
        return instance;
    };
}

當然,像上面這種例子有很多。惰性函數定義,應用場景我們可以總結一下:

1 應用頻繁,如果只用一次,是體現不出它的優點出來的,用的次數越多,越能體現這種模式的優勢所在;

2 固定不變,一次判定,在固定的應用環境中不會發生改變;

3 復雜的分支判斷,沒有差異性,不需要應用這種模式;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM