原文出處:http://yuiblog.com/blog/2007/06/12/module-pattern/
翻譯:Frank
全域變數是一種禍害。在YUI中,我們只使用兩個全域變數YAHOO和YAHOO_config。所有YUI的對象都從YAHOO這個對象層次上訪問成員或屬於這個成員的變數。我們建議你在您的程式中亦效仿此實踐。
Douglas Crockford已經對我們傳授了使用單例的模式(singletion pattern)來實現此模式,而且我認為應用到該模式來構建基於YUI,不乏一些有意思的地方。Douglas稱這個為“”,看看他怎麼做的?
1、建立命名空間對象:如果你使用的YUI,你可以採用的YAHOO.namespace()的方法:
js 代碼
-
- YAHOO.namespace("myProject");
這分配了一個空的myProject對象,是YAHOO的一個成員(但不會覆蓋myProject如果已存在的話)。現在我們可以開始加入YAHOO.myProject成員。
2、從一個匿名函數傳回值,分配到命名空間對象上
js 代碼
-
- YAHOO.myProject.myModule = function () {
- return {
- myPublicProperty: "I'm accessible as YAHOO.myProject.myModule.myPublicProperty.";
- myPublicMethod: function () {
- YAHOO.log("I'm accessible as YAHOO.myProject.myModule.myPublicMethod.");
- }
- };
- }(); //這裡括弧的作用的是 執行該匿名函數並返回
注意花括弧結尾的最底行,後面緊跟著一對括弧() --這符號的含意是立即執行該匿名函數,返回一個包含myPublicProperty和myPublicMethod的對象。只要匿名函數能夠返回,返回的那個對象便可 以YAHOO.myProject.myModule訪問。
3、在匿名函數中優先加入”私人“的方法和變數(在return之前)。
到現在,我們做的只是將myPubilcProperty和myPublicMethod直接分配到YAHOO.myProject.myModule。除此之外,該模式還允許我們在return語之前執行一些代碼:
私人變數如myPrivateProperty和myPrivateMethod的,只能被匿名函數本身,或是返回對象的成員訪問。儘管匿名函數會立即執行和終結,但它們依然是保留著,憑藉閉包(closure)的力量,只要 YAHOO.myProject.myModule需要它們,我們的兩個所以變數就不會被銷毀。
4、實踐該模式我們來看看module pattern的實際應用。假設你有一段列表,列表的上的某些item是可被拖動的。拖動的item有一個draggable的CSS Class。
- <!--This script file includes all of the YUI utilities:-->
- <script type="text/javascript" src="http://yui.yahooapis.com/2.2.2/build/utilities/utilities.js"></script>
-
- <ul id="myList">
- <li class="draggable">Item one.</li>
- <li>Item two.</li> <!--item two won't be draggable-->
- <li class="draggable">Item three.</li>
- </ul>
-
- <script>
- YAHOO.namespace("myProject");
- YAHOO.myProject.myModule = function () {
-
- //引用YUI utilities的簡寫:
- var yue = YAHOO.util.Event,
- yud = YAHOO.util.Dom;
-
- //私人方法
- var getListItems = function () {
-
- //注意我們使用其它的私人變數,包括 "yud"的簡寫
- var elList = yud.get("myList");
- var aListItems = yud.getElementsByClassName(
- "draggable", //擷取只帶有”draggable“CSS類的item
- "li", //只返回列表item
- elList //限制搜尋該元素的children
- );
- return aListItems;
- };
-
- //返回的對象變為YAHOO.myProject.myModule:
- return {
-
- aDragObjects: [], //儲存 DD objects,可對外訪問
-
- init: function () {
- //等到DOM完全載入好,才開始建立列表item:
- yue.onDOMReady(this.makeLIsDraggable, this, true);
- },
-
- makeLIsDraggable: function () {
- var aListItems = getListItems(); //這些元素我們讓它可拖動
- for (var i=0, j=aListItems.length; i<j; i++) {
- this.aDragObjects.push(new YAHOO.util.DD(aListItems[i]));
- }
- }
-
- };
- }(); //這裡括弧的作用的是 執行該匿名函數並返回
-
- //上面的代碼執行完畢,所以我們即可訪問init
- YAHOO.myProject.myModule.init();
- </script>
xml 代碼
這個一個簡單的例子,特意寫得繁瑣一些。如果我們按這種方式做,我們有相信能夠寫出更緊湊的代碼。不過,該模式的伸縮 會隨著項目的複雜度同步增長,API也變得越來越大。使用該方法,避免的了全域的命名空間,而又能對API的方法公用的訪問,支援保護(protected)或”私人“的資料。
js 代碼
-
- YAHOO.myProject.myModule = function () {
- //“私人變數”:
- var myPrivateVar = "I can be accessed only from within YAHOO.myProject.myModule.";
- //“私人方法”:
- var myPrivateMethod = function () {
- YAHOO.log("I can be accessed only from within YAHOO.myProject.myModule");
- }
- return {
- myPublicProperty: "I'm accessible as YAHOO.myProject.myModule.myPublicProperty."
- myPublicMethod: function () {
- YAHOO.log("I'm accessible as YAHOO.myProject.myModule.myPublicMethod.");
- //Within myProject, I can access "private" vars and methods:
- YAHOO.log(myPrivateVar);
- YAHOO.log(myPrivateMethod());
- //The native scope of myPublicMethod is myProject; we can
- //access public members using "this":
- YAHOO.log(this.myPublicProperty);
- }
- };
- }(); //這裡括弧的作用的是 執行該匿名函數並返回
上面的代碼中,我們從一匿名函數返回一個包含兩個成員的對象。在YAHOO.myProject.myModule內可分別用this.myPublicProperty和this.myPublivMethod來訪問。在YAHOO.myProject.myModule外部,這些公告成員可用YAHOO.myProject.myModule.myPublicProperty 和 YAHOO.myProject.myModule.myPublicMethod訪問。