JS惰性載入函數與分支函數

2020-07-16 10:05:05
惰性載入函數和分支函數是 JS 高階函數的兩種具體應用場景,它們都是將函數作為返回值 return 到函數外部。

JS惰性載入函數

惰性載入就是當第 1 次根據條件執行函數後,第 2 次呼叫函數時,就不再檢測條件,直接執行函數。

【問題由來】

由於瀏覽器之間的行為差異,很多指令碼會包含大量的條件檢測,通過條件決定不同行為的瀏覽器執行不同的程式碼。

【設計思路】

  1. 當函數第 1 次被呼叫的時候,執行一次檢測條件。
  2. 在第 1 次呼叫的過程中,使用另外一個根據條件檢測,按合適方式執行的函數,覆蓋掉第 1 次呼叫的函數。
  3. 當再次呼叫該函數時,不再是原來的函數,而是直接呼叫被覆蓋後的函數,這樣就不用再次執行條件檢測了。

範例

在註冊事件處理常式時,經常需要考慮瀏覽器的事件模型。先要檢測當前瀏覽器是 DOM 模型,還是 IE 的事件模型,然後呼叫不同的方法進行註冊。
var addEvent = function (element, type, handle) {
    if (element.addEventListener) {
        element.addEventListener(type, handle, false);
    } else {
        element.attachEvent("on" + type, handle);
    }
}
addEvent(document, "mousemove", function () {
    console.log("移動滑鼠:" + ((this.n) ? (++this.n) : (this.n = 1)));
})
addEvent(window, "resize", function () {
    console.log("改變視窗大小:"+ ((this.n) ? (++this.n) : (this.n = 1)));
})
如此簡單的條件檢測,如果在高頻、巨量的操作中,每次呼叫 addEvent() 方法都需要做一次條件檢測,無疑是不經濟的。下面使用惰性載入方法,重寫 addEvent() 函數。
var addEvent = function (element, type, handle) {
    //先檢測瀏覽器,然後把合適的操作函數覆蓋掉當前addEvent()
    addEvent = element.addEventListener ? function (element, type, handle) {
        element.addEventListener(type, handle, false);
    } : function (element, type, handle) {
        element.attachEvent("on" + type, handle);
    };
    //在第一次執行addEvent函數時,修改了addEvent函數之後,必須執行一次
    addEvent(element, type, handle);
}
在上面程式碼中,當第 1 次呼叫 addEvent() 函數時做一次條件檢測;然後根據瀏覽器選擇相應的事件註冊方法,同時把這個操作封裝在一個匿名函數中;接著使用該函數覆蓋掉 addEvent() 函數;最後執行第 1 次事件註冊操作。這樣,當第 2 次開始再次註冊事件時,就不需要做條件檢測了。

JS分支函數

分支函數與惰性載入函數都是解決條件檢測的問題。分支函數類似物件導向程式設計的介面,對外提供相同的操作介面,內部實現則會根據不同的條件執行不同的操作。分支函數與惰性載入函數在設計原理上是非常相近的,只是在程式碼實現方面略有差異。

範例

使用分支函數解決瀏覽器相容性的重複判斷。解決瀏覽器相容性的一般方法是使用 if 語句進行特性檢測或能力檢測,然後根據瀏覽器的不同,實現功能上的相容。這樣做的問題是,每執行一次程式碼,可能都需要進行一次瀏覽器相容性方面的檢測,這是沒有必要的。

分支函數的設計思路:在程式碼初始化執行的時候檢測瀏覽器的相容性,在之後的程式碼執行過程中,就不再進行檢測。

下面宣告一個 XMLHttpRequest 範例物件。
var XHR = function () {
    var standard = {
        createXHR : function () {
            return new XMLHttpRequest();
        }
    }
    var newActionXObject = {
        createXHR : function () {
            return new ActionXObject("Msxml2.XMLHTTP");
        } 
    }
    var oldActionXObject = {
        createXHR : function () {
            return new ActionXObject("Microsoft.XMLHTTP");
        }
    }
    if (standard.createXHR) {
        return standard;
    } else {
        try {
            newActionXObject.createXHR();
            return newActionXObject;
        } catch {
            oldActionXObject.createXHR();
            return oldActionXObject;
        }
    }
} ();
var xhr = XHR.createXHR();  //建立XMLHttpRequest範例物件
在程式碼初始化執行之後,XHR 被初始化為一個物件,擁有 createXHR() 方法,該方法的實現已經在初始化階段根據當前瀏覽器選擇了合適的方法,當呼叫 XHR.createXHR() 方法建立 XMLHttpRequest 範例物件時,就不再去檢測瀏覽器的相容性問題。