本篇我們介紹的一些模式稱為初始化模式和性能模式,主要是用在初始化以及提高性能方面,一些模式之前已經(jīng)提到過,這里只是做一下總結(jié)。
在本系列第4篇的《立即調(diào)用的函數(shù)表達(dá)式》中,我們已經(jīng)對(duì)類似的函數(shù)進(jìn)行過詳細(xì)的描述,這里我們只是再舉兩個(gè)簡(jiǎn)單的例子做一下總結(jié)。
// 聲明完函數(shù)以后,立即執(zhí)行該函數(shù)
(function () {
console.log('watch out!');
} ());
//這種方式聲明的函數(shù),也可以立即執(zhí)行
!function () {
console.log('watch out!');
} ();
// 如下方式也都可以哦
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();
該模式的意思是指在聲明一個(gè)對(duì)象(而非函數(shù))的時(shí)候,立即執(zhí)行對(duì)象里的某一個(gè)方法來進(jìn)行初始化工作,通常該模式可以用在一次性執(zhí)行的代碼上。
({
// 這里你可以定義常量,設(shè)置其它值
maxwidth: 600,
maxheight: 400,
// 當(dāng)然也可以定義utility方法
gimmeMax: function () {
return this.maxwidth + "x" + this.maxheight;
},
// 初始化
init: function () {
console.log(this.gimmeMax());
// 更多代碼...
}
}).init(); // 這樣就開始初始化咯
分支初始化是指在初始化的時(shí)候,根據(jù)不同的條件(場(chǎng)景)初始化不同的代碼,也就是所謂的條件語句賦值。之前我們?cè)谧鍪录幚淼臅r(shí)候,通常使用類似下面的代碼:
var utils = {
addListener: function (el, type, fn) {
if (typeof window.addEventListener === 'function') {
el.addEventListener(type, fn, false);
} else if (typeof document.attachEvent !== 'undefined') {
el.attachEvent('on' + type, fn);
} else {
el['on' + type] = fn;
}
},
removeListener: function (el, type, fn) {
}
};
我們來改進(jìn)一下,首先我們要定義兩個(gè)接口,一個(gè)用來add事件句柄,一個(gè)用來remove事件句柄,代碼如下:
var utils = {
addListener: null,
removeListener: null
};
實(shí)現(xiàn)代碼如下:
if (typeof window.addEventListener === 'function') {
utils.addListener = function (el, type, fn) {
el.addEventListener(type, fn, false);
};
} else if (typeof document.attachEvent !== 'undefined') { // IE
utils.addListener = function (el, type, fn) {
el.attachEvent('on' + type, fn);
};
utils.removeListener = function (el, type, fn) {
el.detachEvent('on' + type, fn);
};
} else { // 其它舊瀏覽器
utils.addListener = function (el, type, fn) {
el['on' + type] = fn;
};
utils.removeListener = function (el, type, fn) {
el['on' + type] = null;
};
}
用起來,是不是就很方便了?代碼也優(yōu)雅多了。
一般是在函數(shù)內(nèi)部,重寫同名函數(shù)代碼,比如:
var scareMe = function () {
alert("Boo!");
scareMe = function () {
alert("Double boo!");
};
};
這種代碼,非常容易使人迷惑,我們先來看看例子的執(zhí)行結(jié)果:
// 1\. 添加新屬性
scareMe.property = "properly";
// 2\. scareMe賦與一個(gè)新值
var prank = scareMe;
// 3\. 作為一個(gè)方法調(diào)用
var spooky = {
boo: scareMe
};
// 使用新變量名稱進(jìn)行調(diào)用
prank(); // "Boo!"
prank(); // "Boo!"
console.log(prank.property); // "properly" // 使用方法進(jìn)行調(diào)用
spooky.boo(); // "Boo!"
spooky.boo(); // "Boo!"
console.log(spooky.boo.property); // "properly"
通過執(zhí)行結(jié)果,可以發(fā)現(xiàn),將定于的函數(shù)賦值與新變量(或內(nèi)部方法),代碼并不執(zhí)行重載的scareMe代碼,而如下例子則正好相反:
// 使用自聲明函數(shù)
scareMe(); // Double boo!
scareMe(); // Double boo!
console.log(scareMe.property); // undefined
大家使用這種模式時(shí),一定要非常小心才行,否則實(shí)際結(jié)果很可能和你期望的結(jié)果不一樣,當(dāng)然你也可以利用這個(gè)特殊做一些特殊的操作。
該模式主要是利用函數(shù)的屬性特性來避免大量的重復(fù)計(jì)算。通常代碼形式如下:
var myFunc = function (param) {
if (!myFunc.cache[param]) {
var result = {};
// ... 復(fù)雜操作 ...
myFunc.cache[param] = result;
}
return myFunc.cache[param];
};
// cache 存儲(chǔ)
myFunc.cache = {};
但是上述代碼有個(gè)問題,如果傳入的參數(shù)是toString或者其它類似Object擁有的一些公用方法的話,就會(huì)出現(xiàn)問題,這時(shí)候就需要使用傳說中的hasOwnProperty
方法了,代碼如下:
var myFunc = function (param) {
if (!myFunc.cache.hasOwnProperty(param)) {
var result = {};
// ... 復(fù)雜操作 ...
myFunc.cache[param] = result;
}
return myFunc.cache[param];
};
// cache 存儲(chǔ)
myFunc.cache = {};
或者如果你傳入的參數(shù)是多個(gè)的話,可以將這些參數(shù)通過JSON的stringify方法生產(chǎn)一個(gè)cachekey值進(jìn)行存儲(chǔ),代碼如下:
var myFunc = function () {
var cachekey = JSON.stringify(Array.prototype.slice.call(arguments)),
result;
if (!myFunc.cache[cachekey]) {
result = {};
// ... 復(fù)雜操作 ...
myFunc.cache[cachekey] = result;
}
return myFunc.cache[cachekey];
};
// cache 存儲(chǔ)
myFunc.cache = {};
或者多個(gè)參數(shù)的話,也可以利用arguments.callee特性:
var myFunc = function (param) {
var f = arguments.callee,
result;
if (!f.cache[param]) {
result = {};
// ... 復(fù)雜操作 ...
f.cache[param] = result;
}
return f.cache[param];
};
// cache 存儲(chǔ)
myFunc.cache = {};
就不用總結(jié)了吧,大家仔細(xì)看代碼就行咯
更多建議: