## 介紹
本篇我們介紹的一些模式稱為初始化模式和性能模式,主要是用在初始化以及提高性能方面,一些模式之前已經提到過,這里只是做一下總結。
## 立即執行的函數
在本系列第4篇的《[立即調用的函數表達式](http://www.cnblogs.com/TomXu/archive/2011/12/31/2289423.html)》中,我們已經對類似的函數進行過詳細的描述,這里我們只是再舉兩個簡單的例子做一下總結。
~~~
// 聲明完函數以后,立即執行該函數
(function () {
console.log('watch out!');
} ());
//這種方式聲明的函數,也可以立即執行
!function () {
console.log('watch out!');
} ();
// 如下方式也都可以哦
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();
~~~
## 立即執行的對象初始化
該模式的意思是指在聲明一個對象(而非函數)的時候,立即執行對象里的某一個方法來進行初始化工作,通常該模式可以用在一次性執行的代碼上。
~~~
({
// 這里你可以定義常量,設置其它值
maxwidth: 600,
maxheight: 400,
// 當然也可以定義utility方法
gimmeMax: function () {
return this.maxwidth + "x" + this.maxheight;
},
// 初始化
init: function () {
console.log(this.gimmeMax());
// 更多代碼...
}
}).init(); // 這樣就開始初始化咯
~~~
## 分支初始化
分支初始化是指在初始化的時候,根據不同的條件(場景)初始化不同的代碼,也就是所謂的條件語句賦值。之前我們在做事件處理的時候,通常使用類似下面的代碼:
~~~
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) {
}
};
~~~
我們來改進一下,首先我們要定義兩個接口,一個用來add事件句柄,一個用來remove事件句柄,代碼如下:
~~~
var utils = {
addListener: null,
removeListener: null
};
~~~
實現代碼如下:
~~~
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;
};
}
~~~
用起來,是不是就很方便了?代碼也優雅多了。
## 自聲明函數
一般是在函數內部,重寫同名函數代碼,比如:
~~~
var scareMe = function () {
alert("Boo!");
scareMe = function () {
alert("Double boo!");
};
};
~~~
這種代碼,非常容易使人迷惑,我們先來看看例子的執行結果:
~~~
// 1\. 添加新屬性
scareMe.property = "properly";
// 2\. scareMe賦與一個新值
var prank = scareMe;
// 3\. 作為一個方法調用
var spooky = {
boo: scareMe
};
// 使用新變量名稱進行調用
prank(); // "Boo!"
prank(); // "Boo!"
console.log(prank.property); // "properly" // 使用方法進行調用
spooky.boo(); // "Boo!"
spooky.boo(); // "Boo!"
console.log(spooky.boo.property); // "properly"
~~~
通過執行結果,可以發現,將定于的函數賦值與新變量(或內部方法),代碼并不執行重載的scareMe代碼,而如下例子則正好相反:
~~~
// 使用自聲明函數
scareMe(); // Double boo!
scareMe(); // Double boo!
console.log(scareMe.property); // undefined
~~~
大家使用這種模式時,一定要非常小心才行,否則實際結果很可能和你期望的結果不一樣,當然你也可以利用這個特殊做一些特殊的操作。
## 內存優化
該模式主要是利用函數的屬性特性來避免大量的重復計算。通常代碼形式如下:
~~~
var myFunc = function (param) {
if (!myFunc.cache[param]) {
var result = {};
// ... 復雜操作 ...
myFunc.cache[param] = result;
}
return myFunc.cache[param];
};
// cache 存儲
myFunc.cache = {};
~~~
但是上述代碼有個問題,如果傳入的參數是toString或者其它類似Object擁有的一些公用方法的話,就會出現問題,這時候就需要使用傳說中的`hasOwnProperty`方法了,代碼如下:
~~~
var myFunc = function (param) {
if (!myFunc.cache.hasOwnProperty(param)) {
var result = {};
// ... 復雜操作 ...
myFunc.cache[param] = result;
}
return myFunc.cache[param];
};
// cache 存儲
myFunc.cache = {};
~~~
或者如果你傳入的參數是多個的話,可以將這些參數通過JSON的stringify方法生產一個cachekey值進行存儲,代碼如下:
~~~
var myFunc = function () {
var cachekey = JSON.stringify(Array.prototype.slice.call(arguments)),
result;
if (!myFunc.cache[cachekey]) {
result = {};
// ... 復雜操作 ...
myFunc.cache[cachekey] = result;
}
return myFunc.cache[cachekey];
};
// cache 存儲
myFunc.cache = {};
~~~
或者多個參數的話,也可以利用arguments.callee特性:
~~~
var myFunc = function (param) {
var f = arguments.callee,
result;
if (!f.cache[param]) {
result = {};
// ... 復雜操作 ...
f.cache[param] = result;
}
return f.cache[param];
};
// cache 存儲
myFunc.cache = {};
~~~
## 總結
就不用總結了吧,大家仔細看代碼就行咯
- (1)編寫高質量JavaScript代碼的基本要點
- (2)揭秘命名函數表達式
- (3)全面解析Module模式
- (4)立即調用的函數表達式
- (5)強大的原型和原型鏈
- (6)S.O.L.I.D五大原則之單一職責SRP
- (7)S.O.L.I.D五大原則之開閉原則OCP
- (8)S.O.L.I.D五大原則之里氏替換原則LSP
- (9)根本沒有“JSON對象”這回事!
- (10)JavaScript核心(晉級高手必讀篇)
- (11)執行上下文(Execution Contexts)
- (12)變量對象(Variable Object)
- (13)This? Yes, this!
- (14)作用域鏈(Scope Chain)
- (15)函數(Functions)
- (16)閉包(Closures)
- (17)面向對象編程之一般理論
- (18)面向對象編程之ECMAScript實現
- (19)求值策略
- (20)《你真懂JavaScript嗎?》答案詳解
- (21)S.O.L.I.D五大原則之接口隔離原則ISP
- (22)S.O.L.I.D五大原則之依賴倒置原則DIP
- (23)JavaScript與DOM(上)——也適用于新手
- (24)JavaScript與DOM(下)
- (25)設計模式之單例模式
- (26)設計模式之構造函數模式
- (27)設計模式之建造者模式
- (28)設計模式之工廠模式
- (29)設計模式之裝飾者模式
- (30)設計模式之外觀模式
- (31)設計模式之代理模式
- (32)設計模式之觀察者模式
- (33)設計模式之策略模式
- (34)設計模式之命令模式
- (35)設計模式之迭代器模式
- (36)設計模式之中介者模式
- (37)設計模式之享元模式
- (38)設計模式之職責鏈模式
- (39)設計模式之適配器模式
- (40)設計模式之組合模式
- (41)設計模式之模板方法
- (42)設計模式之原型模式
- (43)設計模式之狀態模式
- (44)設計模式之橋接模式
- (45)代碼復用模式(避免篇)
- (46)代碼復用模式(推薦篇)
- (47)對象創建模式(上篇)
- (48)對象創建模式(下篇)
- (49)Function模式(上篇)
- (50)Function模式(下篇)
- (結局篇)