劃分命名空間 單體對象由兩個部分組成:包含方法和屬性成員的對象自身,以及用於訪問它的變數。 它提供了一種將程式碼群組織為一個邏輯單元的手段,這個邏輯單元中的代碼可以通過單一的變數進行訪問(通過確保單體對象只存在一份執行個體,你就可以確信自己的所有代碼使用的都是同樣的全域資源)。 命名空間是可靠地JavaScript編程的一個重要工具。把相關的方法組織到一起,也助於增強代碼的文檔性。 JavaScript 的命名空間並不是真正的命名空間, 只是在指令碼內部建立一個封閉的小空間, 必須通過特定的空間名稱才能對空間內部的代碼進行訪問, 這樣可以防止同名函數和變數發生衝突, 也可以更方便地管理代碼, 就像 .NET 的命名空間 (namespace) 和 Java 的包 (package) 一樣. 用作特定頁面專用代碼的封裝器 在擁有許多網頁的網站中,有些JavaScript代碼是所有網頁都要用到的,它們通常被存放在獨立的檔案中;而有些代碼則是某個頁面專用的,不會被用到其他地方。最好把這兩種代碼分別封裝在自己的單體對象中。 具體做法:封裝一些資料(也許是作為常量)、為各頁面的行為定義一些方法以及初始化方法。涉及DOM中特有元素的大多數代碼,比如添加事件監聽的代碼,只有在這些元素載入之後才能工作。你可以通過建立一個init方法並將其關聯到視窗的load事件(或類似的其他事件,如DOMContentLoaded事件),將所有這些初始化程式碼群組織到一個地方。 /* Generic page Object */var Namespace = {};Namespace.PageName = { //頁面常量constants CONSTANT_1: true, CONSTANT_2: 10, //Page methods method1: function() { //... }, method2: function(arg) { //... }, //可以把與DOM打交道的程式放在這裡 init: function() { //... }}; addLoadEvent(Namespace.PageName.init); 建立私人成員 擁有真正的私人方法的一個缺點在於它們比較耗費記憶體,因為每個執行個體都具有方法的一份新副本。不過,由於單體對象只會被執行個體一次,因此為其定義真正的私人方法時不必考慮記憶體方面的問題。 /* 建立擁有私人成員單體的結構 */var Namespace = {}; //自訂命名空間Namespace.Singleton = {}; /* 用定義後立即執行函數建立單體 */Namespace.Singleton = (function() { //... return {}; //返回字面量對象})(); 下面是一個具體的執行個體,描述了擁有私人方法單體的使用。 //使用閉包建立私人成員Namespace.DataParse = (function() { //private method function stripWhitespace(str) { return str.replace(/\s+/g, ''); } function stringSplit(str, delimiter) { return str.split(delimiter); } //特權方法 return { stringToArray: function(str, delimiter, stripWS) { if(stripWS) { str = stripWhitespace(str); } return stringSplit(str, delimiter); } }})(); 這種單體模式又稱模組模式:它可以把一批相關的方法和屬性群組織為模組並起到劃分命名空間的作用。 使用這種模式時,你可以享受到真正的私人成員帶來的所有好處,而不必付出什麼代價。這是因為單體類只會執行個體化一次。 單體中使用分支技術 一種用來把瀏覽器間的差異封裝到在運行期間進行設定的動態方法中的技術。 var Namespace = {};Namespace.Singleton = (function() { var objectA = { method1: function() {}, method2: function() {} }; var objectB = { method1: function() {}, method2: function() {} }; return (someCondtion)? objectA:objectB; })(); 分支技術並不總是更高效的選擇。在前面的例子中,有兩個對象(objectA和objectB)被建立出來並儲存在記憶體中,但派上用場的只有一個。在考慮是否使用這個技術的時候,廈門www.fpshamen.com,需要在縮短計算時間和佔用更多記憶體這一利一弊之間權衡一下。 樣本:用分支技術建立XHR對象 var SimpleXHRFactory = (function() { //下面有三種情況,三個分支 var standard = { createXhrObject: function() { return new XMLHttpRequest(); } }; var activeXNew = { createXhrObject: function() { return new ActiveXObject('Msxml2.XMLHTTP'); } }; var activeXOld = { createXhrObject: function() { return new ActiveXObject('Microsoft.XMLHTTP'); } }; //利用try...catche判斷適合的XHR對象 var XHR = null; try{ XHR = standard.createXhrObject(); return standard; //如果沒有錯誤拋出,將返回該對象 }catch(e){ try { XHR = activeXNew.createXhrObject(); return activeXNew; }catch(e) { try { XHR = activeXOld.createXhrObject(); return activeXOld; }catch(e) { throw new Error('無法建立XHR對象'); } } }})(); //--------------------- test -------console.log(SimpleXHRFactory.createXhrObject());console.log(SimpleXHRFactory.createXhrObject()); 單體模式提供的只是一種單點訪問,有可能會導致模組間的強耦合。有時建立一個可執行個體化的類更可取,哪怕它只會被執行個體化一次。 有時候某種更高的模式會更符合任務的需要。與惰性載入單例相比,虛擬代理能給予對類執行個體化方式更多的控制權。也可以用原廠模式來取代分支型單體。