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