深入理解javascript函式進階系列第四篇——惰性函式

weixin_34119545發表於2017-12-12

前面的話

  惰性函式表示函式執行的分支只會在函式第一次呼叫的時候執行,在第一次呼叫過程中,該函式會被覆蓋為另一個按照合適方式執行的函式,這樣任何對原函式的呼叫就不用再經過執行的分支了。本文將詳細介紹惰性函式

 

使用背景

  因為各瀏覽器之間的行為的差異,經常會在函式中包含了大量的if語句,以檢查瀏覽器特性,解決不同瀏覽器的相容問題。比如,最常見的為dom節點新增事件的函式

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函式的時候,它都要對瀏覽器所支援的能力進行檢查,首先檢查是否支援addEventListener方法,如果不支援,再檢查是否支援attachEvent方法,如果還不支援,就用dom0級的方法新增事件

  這個過程,在addEvent函式每次呼叫的時候都要走一遍,其實,如果瀏覽器支援其中的一種方法,那麼它就會一直支援了,就沒有必要再進行其他分支的檢測了。也就是說,if語句不必每次都執行,程式碼可以執行的更快一些

  解決方案就是惰性載入

 

函式重寫

  在介紹惰性函式之前,首先介紹函式重寫技術。由於一個函式可以返回另一個函式,因此可以用新的函式來覆蓋舊的函式

function a(){
    console.log('a');
    a = function(){
        console.log('b');
    }
}

  這樣一來,第一次呼叫該函式時會console.log('a')會被執行;全域性變數a被重定義,並被賦予新的函式。當該函式再次被呼叫時, console.log('b')會被執行

 

惰性函式

  惰性函式的本質就是函式重寫。所謂惰性載入,指函式執行的分支只會發生一次,有兩種實現惰性載入的方式

  1、第一種是在函式被呼叫時,再處理函式。函式在第一次呼叫時,該函式會被覆蓋為另外一個按合適方式執行的函式,這樣任何對原函式的呼叫都不用再經過執行的分支了。程式碼重寫如下

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()中,if語句的每個分支都會為addEvent變數賦值,有效覆蓋了原函式。最後一步便是呼叫了新賦函式。下一次呼叫addEvent()時,便會直接呼叫新賦值的函式,這樣就不用再執行if語句了

  但是,這種方法有個缺點,如果函式名稱有所改變,修改起來比較麻煩

  2、第二種是宣告函式時就指定適當的函式。把嗅探瀏覽器的操作提前到程式碼載入的時候,在程式碼載入的時候就立刻進行一次判斷,以便讓addEvent返回一個包裹了正確邏輯的函式

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

 

相關文章