|
Module Pattern是由Javascript資深大師Douglas Crockford所提出,最早在2007年時YUI的部落格「A JavaScript Module Pattern」上,有一位工程師Eric Miraglia作了詳盡的說明和範例。之後Douglas Crockford在他的書「JavaScript: The Good Parts」中,也有提到這個部份,這個章節標題為「Module」,摘錄其中一段對於Module的定義說明:
We can use functions and closure to make modules. A module is a function or object that presents an interface but that hides its state and implementation. By using functions to produce modules, we can almost completely eliminate our use of global variables, thereby mitigating one of JavaScript's worst features.
Eric Miraglia在部落格上的第一句話也說:
綜合上面所說明的,這個Module Pattern是由函數和閉包所組成,可以隱藏其中的變數和實作方法(一種封裝),當然,這也是一種避免(或減少)Javascript全局變量的設計模式。本篇收集整理了一些有關模組設計模式的資料和範例:
除了閉包的知識要掌握之外,其中也會搭配匿名函數(Anonymous),Ben Cherry稱下面的用法為匿名閉包(出自: JavaScript Module Pattern: In-Depth):
1
2
3
4
|
(function () {
// ... all vars and functions are in this scope only
// still maintains access to all globals
}());
|
你可以對照一下匿名函數的立即執行版本如下,差異在最後的括號的地方:
1
2
3
|
(function () {
//anonymous function immediately executed
})();
|
但是如果是直接寫成下面這樣,就是一個statement(指令),而非expression(語句),是不能直接只寫這句就使用,需要加上賦值的部份(註:expressions are evaluated to some value, while statements have no evaluated value.)
1
2
3
|
function () {
//anonymous function immediately executed
}();
|
其實下面這兩種方式的執行結果是相等的,至於為何要學習這個方式?其實只是一種主張要更清楚表示的寫作風格而已。
1
2
3
4
5
6
7
|
var a=function(){
//code
}();
var a=(function(){
//code
}());
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
var classicModulePattern = function(){
var privateVar = 1;
function privateFunction(){
alert('private');
}
return {
publicVar:2,
publicFunction:function(){
classicModulePattern.anotherPublicFunction(); //=this.xxx
},
anotherPublicFunction:function(){
privateFunction();
}
}
}();
classicModulePattern.publicFunction();
|
說明:
- 模組最後是匿名函式的立即執行(有「( )」),代表這也是個singleton的設計模式
- 私有屬性和方法,在模組裡可以直接存取,在外部不能存取
- 公有屬性和方法(在return的大括號之中),在內部要用「模組名.屬性」或「模組名.方法」來存取(用this取代模組名也可以)
- 公有屬性和方法(在return的大括號之中),每一個的區隔是用逗號「,」,賦值是用「:」(對照原來是用斷行區隔,賦值用=號)
為了更清楚表示,以及使用this或模組名的存取公有屬性和方法,造成撰寫的麻煩,利用一個名為pub的物件取代return中的公有屬性和方法,經過加工後的模組如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
var namedObjectModulePattern = function(){
var pub = {};
var privateVar = 1;
function privateFunction(){
alert('private');
};
pub.publicVar = 2;
pub.publicFunction = function(){
pub.anotherPublicFunction();
};
pub.anotherPublicFunction = function(){
privateFunction();
};
return pub;
}();
namedObjectModulePattern.publicFunction();
|
因為Javascript甚至連物件都可以是匿名的,乾脆更簡化,使用匿名物件,把所有的屬性和方法都寫成私有,然後利用匿名物件"泄露"出來。匿名物件中的屬性和方法名都可以更改,也可以直接把屬性賦值進去:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
var revealingModulePattern = function(){
var privateVar = 1;
function privateFunction(){
alert('private');
};
var publicVar = 2;
function publicFunction(){
anotherPublicFunction();
};
function anotherPublicFunction(){
privateFunction();
};
function getCurrentState(){
return 2;
};
// reveal all things private by assigning public pointers
return {
init:publicFunction,
count:publicVar,
increase:anotherPublicFunction,
current:getCurrentState()
}
}();
alert(revealingModulePattern.current); // => 2
revealingModulePattern.init();
|
更進階的模組設計模式,可以看「JavaScript Module Pattern: In-Depth」這篇文章。
評論: |