前面的話
惰性函式表示函式執行的分支只會在函式第一次呼叫的時候執行,在第一次呼叫過程中,該函式會被覆蓋為另一個按照合適方式執行的函式,這樣任何對原函式的呼叫就不用再經過執行的分支了。本文將詳細介紹惰性函式
使用背景
因為各瀏覽器之間的行為的差異,經常會在函式中包含了大量的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; } } })();