9.2Module(模塊)模式
通常能夠幫助我們清晰地分離和組織項目中的代碼單元
js中實現模塊的方法
1》對象字面量表示法
2》Module模式
3》AMD模式
4》CommonJS模塊
5》ECMAScript Harmony模塊
Module模式某種程度上是基於對象的字面量
9.2.1對象字面量
在對象字面量表示法中,一個對象被描述為一組包含在大括號{}中、以逗號分隔的name/value對。對象內的名稱可以是字符串或標識符,后面跟着一個冒號。對象中最后的一個name/value對的后面不用加逗號,如果加逗號將會導致出錯。
Var myObjectLiteral={
variableKey:variableValue;
functionKey:function(){
//
}
};
對象字面量不需要使用new運算符進行實例化,但不能用在一個語句的開頭,因為開始的可能被解讀為一個塊的開始。在對象的外部,新成員可以使用如下賦值語句添加在字面量上,如:
myModule.property="some Value";
使用對象字面量有助於封裝和組織代碼,Module模式仍然使用對象字面量,但只是作為一個作用域函數的返回值。
var myModule={ myProperty:"somevalue", //對象字面量可以包含屬性和方法 //例如,可以聲明模塊的配置對象 myConfig:{ useCaching:true, language:"en" }, //基本方法 myMethod:function(){ console.log("myMethod"); }, //根據當前配置輸出信息 myMethod2:function(){ console.log("caching is:" + (this.myConfig.useCaching) ? "enabled":"disabled"); }, //重寫當前配置 myMethod3:function(newConfig){ if(typeof newConfig==="object"){ this.myConfig=newConfig; console.log(this.myConfig.language); } } }; myModule.myMethod(); myModule.myMethod2();//打印出來的是enabled,沒有加上前面的字符串 myModule.myMethod3({ language:"fr", useCaching:false });
9.2.2Module(模塊)模式
Module模式最初被定義為一種在傳統軟件工程中為類提供私有和公有封裝的方法。
在js中,Module模式用於進一步模擬類的概念,通過這種方式,能夠使一個單獨的對象用於公有/私有方法和變量,從而屏蔽來自全局作用域的特殊部分。產生的結果是:函數名與在頁面上其他腳本定義的函數沖突的可能性降低。
模塊模式的模板
var myNamespace=(function(){ //私有計數器變量 var myPrivateVar=0; //記錄所有參數的私有函數 var myPrivateMethod=function(foo){ console.log(foo); } return{ //公有變量 myPublicVar:"foo", //調用私有變量和方法的公有函數 myPublicFunction:function(bar){ //增加私有計數器值 myPrivateVar++; //傳入bar調用私有方法 myPrivateMethod(bar); } }; })();
9.2.2.1 私有
Module模式使用閉包封裝“私有”狀態和組織。它提供了一種包裝混合公有/私有方法和變量的方式,防止其泄露至全局作用域,並與別的開發人員的接口發生沖突。通過該模式,只需返回一個公有API,而其他的一切則都維持在私有閉包里 。
這為我們提供了一個屏蔽處理底層時間邏輯的整潔解決方案,同時只暴露一個接口供應用程序的其他部分使用。該模式除了返回一個對象而並不是函數之外,非常類似於一個立即調用的函數表達式。
應該指出的是,在js中沒有正真意義上的“私有”,因為js沒有訪問修飾符,因此我們使用函數作用域來模擬這個概念。在Module模式內:閉包聲明的變量和方法只在該模式內部可用。但在返回對象上定義的變量和方法,則對外部使用者都是可用的。
var basketModule=(function(){ //私有 var basket=[]; function doSomethingPrivate(){ console.log("private"); } function doSomethingElsePrivate(){ // } //返回一個暴露出的公有對象 return{ //添加item到購物車 addItem:function(values){ basket.push(values); }, //獲取購物車里的item數 getItemCount:function(){ return basket.length; }, //私有函數的公有形式別名, // doSomething:doSomethingPrivate自動調用doSomethingPrivate函數 doSomething:doSomethingPrivate, //獲取購物車里所有item的價格總值 getTotal:function(){ var itemCount=this.getItemCount(),total=0; while(itemCount--){ total+=basket[itemCount].price; } return total; } }; })(); //basketModule返回了一個擁有公用API的對象 basketModule.addItem({ item:"bread", price: 0.5 }); basketModule.addItem({ item:"butter", price:0.3 }); console.log(basketModule.getItemCount()); console.log(basketModule.getTotal()); //會打印一個private和一個undefined,原因不明 console.log(basketModule.doSomething()); console.log(basketModule.basket);
basket模塊的優點:
1》只有模塊自身才能享有擁有私有函數的自由,因為它只會暴露我們輸出的API。
2》鑒於函數往往已聲明並命名,在試圖找到哪些函數拋出異常時,這將使得在調試器中顯示調用堆棧變得更容易。(沒感覺)
3》根據環境,還可以讓我們返回不同 的函數
9.2.2.3 示例
/** * counter的存在被局限在模塊的閉包內,唯一能訪問其作用域的代碼是return中的2個函數 */ var testModule=(function(){ var counter=0; return{ incrementCounter:function(){ return ++counter; }, resetCounter:function(){ console.log("counter value prior to reset "+counter); counter=0; } }; })(); //增加計數器 testModule.incrementCounter(); //檢查並重置計數器 testModule.resetCounter();
//引入混入 var myModule=(function(jQ,_){ function privateMethod1(){ jQ(".container").html("test"); } return{ publicMethod:function(){ privateMethod1(); } }; //引入JQuery和Underscore })(jQuery,_);