惰性載入函數和分支函數是 JS 高階函數的兩種具體應用場景,它們都是將函數作為返回值 return 到函數外部。
JS惰性載入函數
惰性載入就是當第 1 次根據條件執行函數後,第 2 次呼叫函數時,就不再檢測條件,直接執行函數。
【問題由來】
由於瀏覽器之間的行為差異,很多指令碼會包含大量的條件檢測,通過條件決定不同行為的瀏覽器執行不同的程式碼。
【設計思路】
-
當函數第 1 次被呼叫的時候,執行一次檢測條件。
-
在第 1 次呼叫的過程中,使用另外一個根據條件檢測,按合適方式執行的函數,覆蓋掉第 1 次呼叫的函數。
-
當再次呼叫該函數時,不再是原來的函數,而是直接呼叫被覆蓋後的函數,這樣就不用再次執行條件檢測了。
範例
在註冊事件處理常式時,經常需要考慮瀏覽器的事件模型。先要檢測當前瀏覽器是 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 範例物件時,就不再去檢測瀏覽器的相容性問題。