前端開(kāi)發(fā)者進(jìn)階之惰性函數(shù)定義
穆乙:http://www.rzrgm.cn/pigtail/p/3447660.html
函數(shù)是js世界的一等公民,js的動(dòng)態(tài)性、易變性在函數(shù)的應(yīng)用上,體現(xiàn)的淋漓盡致。做為參數(shù),做為返回值等,正是函數(shù)這些特性,使得js開(kāi)發(fā)變的有趣。
下面就闡述一下,js一個(gè)有趣的應(yīng)用--惰性函數(shù)定義(Lazy Function Definition)。
惰性載入表示函數(shù)執(zhí)行的分支只會(huì)在函數(shù)第一次掉用的時(shí)候執(zhí)行,在第一次調(diào)用過(guò)程中,該函數(shù)會(huì)被覆蓋為另一個(gè)按照合適方式執(zhí)行的函數(shù),這樣任何對(duì)原函數(shù)的調(diào)用就不用再經(jīng)過(guò)執(zhí)行的分支了。
下面我們看幾個(gè)典型的例子:
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; } }
上面是注冊(cè)函數(shù)監(jiān)聽(tīng)的各瀏覽器兼容函數(shù)。由于,各瀏覽之間的差異,不得不在用的時(shí)候做能力檢測(cè)。顯然,單從功能上講,已經(jīng)做到了兼容瀏覽器。美中不足,每次綁定監(jiān)聽(tīng),都會(huì)對(duì)能力做一次檢測(cè)。然而,真正的應(yīng)用中,這顯然是多余的,同一個(gè)應(yīng)用環(huán)境中,其實(shí)只需要檢測(cè)一次即可。
下面我們重寫(xiě)上面的addEvent:
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); }
由上,第一次調(diào)用addEvent會(huì)對(duì)瀏覽器做能力檢測(cè),然后,重寫(xiě)了addEvent。下次再調(diào)用的時(shí)候,由于函數(shù)被重寫(xiě),不會(huì)再做能力檢測(cè)。
同樣的應(yīng)用,javascript高級(jí)程序設(shè)計(jì)里的一例子:
function createXHR(){ if (typeof XMLHttpRequest != "undefined"){ return new XMLHttpRequest(); } else if (typeof ActiveXObject != "undefined"){ if (typeof arguments.callee.activeXString != "string"){ var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"]; for (var i=0,len=versions.length; i < len; i++){ try { var xhr = new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; return xhr; } catch (ex){ //skip } } } return new ActiveXObject(arguments.callee.activeXString); } else { throw new Error("No XHR object available."); } }
很顯然,惰性函數(shù)在這里優(yōu)勢(shì)更加明顯,因?yàn)檫@里有更多的分支。下面我們看一下重寫(xiě)后臺(tái)的函數(shù):
function createXHR() { if (typeof XMLHttpRequest != "undefined") { createXHR = function () { return new XMLHttpRequest(); } return new XMLHttpRequest(); } else if (typeof ActiveXObject != "undefined") { var curxhr; var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"]; for (var i = 0, len = versions.length; i < len; i++) { try { var xhr = new ActiveXObject(versions[i]); curxhr = versions[i]; createXHR = function () { return new ActiveXObject(curxhr); } return xhr; } catch (ex) { //skip } } } else { throw new Error("No XHR object available."); } }
瀏覽器之間最大的差異,莫過(guò)于Dom操作,Dom操作也是前端應(yīng)用 中最頻繁的操作,前端的大多性能提升,均體現(xiàn)在Dom操作方面。下面看一個(gè)Dom操作方面的惰性函數(shù)定義例子:
var getScrollY = function() { if (typeof window.pageYOffset == 'number') { getScrollY = function() { return window.pageYOffset; }; } else if ((typeof document.compatMode == 'string') && (document.compatMode.indexOf('CSS') >= 0) && (document.documentElement) && (typeof document.documentElement.scrollTop == 'number')) { getScrollY = function() { return document.documentElement.scrollTop; }; } else if ((document.body) && (typeof document.body.scrollTop == 'number')) { getScrollY = function() { return document.body.scrollTop; } } else { getScrollY = function() { return NaN; }; } return getScrollY(); }
惰性函數(shù)定義應(yīng)用還體現(xiàn)在創(chuàng)建單例上:
unction Universe() { // 緩存的實(shí)例 var instance = this; // 其它內(nèi)容 this.start_time = 0; this.bang = "Big"; // 重寫(xiě)構(gòu)造函數(shù) Universe = function () { return instance; }; }
當(dāng)然,像上面這種例子有很多。惰性函數(shù)定義,應(yīng)用場(chǎng)景我們可以總結(jié)一下:
1 應(yīng)用頻繁,如果只用一次,是體現(xiàn)不出它的優(yōu)點(diǎn)出來(lái)的,用的次數(shù)越多,越能體現(xiàn)這種模式的優(yōu)勢(shì)所在;
2 固定不變,一次判定,在固定的應(yīng)用環(huán)境中不會(huì)發(fā)生改變;
3 復(fù)雜的分支判斷,沒(méi)有差異性,不需要應(yīng)用這種模式;

浙公網(wǎng)安備 33010602011771號(hào)