在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ 命名空間模式
中介者模式
MVVM
亨元模式
設(shè)計模式分類概覽表
ES Harmony
組合模式
CommonJS
jQuery 插件的設(shè)計模式
外觀模式
觀察者模式
建造者模式
構(gòu)造器模式
外觀模式
簡介
AMD
原型模式
設(shè)計模式的分類
觀察者模式
命名空間模式
代理模式
編寫設(shè)計模式
適配器模式
反模式
什么是設(shè)計模式
模塊化模式
MVC
Mixin 模式
裝飾模式
設(shè)計模式的結(jié)構(gòu)
單例模式
迭代器模式
命令模式
工廠模式
MVP
暴露模塊模式
惰性初始模式

命名空間模式

在這一節(jié)中,我們將探索JavaScript中關(guān)于命名空間的模式。命名空間可被看作位于一個唯一標識符下的代碼單元的邏輯組合。標識符可以被很多命名空間引用,每一個命名空間本身可以包含一個分支的嵌套命名空間(或子命名空間)。

在應(yīng)用開發(fā)過程中,出于很多原因,我們都要使用命名空間。在JavaScript中,它們幫助我們避免在全局空間中于其他對象或者變量出現(xiàn)沖突。它們對于在代碼庫中組織功能塊也非常有用,這樣使用代碼就更容易被使用。

將任何重要的腳本或者應(yīng)用納入命名空間是非常重要的,因為這是我們代碼的一層重要保護,使其免于與頁面中使用相同變量或方法名的其它腳本發(fā)生沖突?,F(xiàn)在由于許多第三方標記規(guī)律的插入頁面,這可能是我們在職業(yè)生涯的某個時刻都需要處理的一個普遍的問題。作為一個行為端正的全局命名空間的“公民”,同樣重要的是,因為同樣的問題,我們最好不要阻礙其他開發(fā)人員的腳本運行。

雖然JavaScript并沒有像其它語言一樣真正內(nèi)置的支持名稱空間,它具有對象和閉包,也可以用來達到相似的效果。

命名空間原理

幾乎所有重要的 Javascript 程序中都會用到命名空間。除非我們只是編寫簡單的代碼,否則盡力確保正確地實現(xiàn)命名空間是很有必要的。這也能避免自己的代碼收到第三方代碼的污染。本小節(jié)將闡述以下設(shè)計模式:

  1. 單一全局變量
  2. 對象序列化的表示
  3. 內(nèi)嵌的命名空間
  4. 即時調(diào)用的函數(shù)表達式
  5. 命名空間注入

單一全局變量

在 JavaScript 中實現(xiàn)命名空間的一個流行模式是,選擇一個全局變量作為引用的主對象。下面顯示的是此方法的框架實現(xiàn),示例代碼中返回一個包含函數(shù)和屬性的對象:

var myApplication =  (function () {
        function(){
            //...
        },
        return{
            //...
        }
})();

雖然這段代碼能在特定的環(huán)境下運行,單一全局變量模式的最大挑戰(zhàn)是如何確保同一頁面中的其他代碼不會使用相同的全局變量名稱。

前綴命名空間

一個解決上面所述問題的方法,正如Peter Michaux提到的, 是使用前綴命名空間. 它本質(zhì)上是一個簡單的概念,但原理是,我們選擇一個我們想用的(這個例子中我們用的是myApplication_)唯一的前綴命名空間,然后在這個前綴的后面定義任意的方法,變量或者其他對象,就像下面一樣:

var myApplication_propertyA = {};
var myApplication_propertyB = {};
function myApplication_myMethod(){
  //...
}

從減少全局變量的角度來講這是非常有效的,但請記住,使用一個具有唯一命名的對象也能達到同樣的效果。

另一方面,這種模式的最大問題在于,一旦我們的應(yīng)用開始增長,它會產(chǎn)生大量的全局對象。全局區(qū)域中對于我們沒有被其他開發(fā)人員使用的前綴也存在嚴重的依賴,所以當你選擇使用的時候,一定要小心。

對象文字表示

對象文字表示(我們在本書的模塊模式一節(jié)中也提到過)可被認為是一個對象包含了一個集合,這個集合中存儲的是鍵值對,它們使用分號將每個鍵值對的鍵和值分隔開,這樣這些鍵也可以表示新的命名空間。

var myApplication = {

    // As we've seen, we can easily define functionality for
    // this object literal..
    getInfo:function(){
      //...
    },

    // but we can also populate it to support
    // further object namespaces containing anything
    // anything we wish:
    models : {},
    views : {
        pages : {}
    },
    collections : {}
};

你也可以直接給命名空間添加屬性:

myApplication.foo = function(){
    return "bar";
}

myApplication.utils = {
    toString:function(){
        //...
    },
    export: function(){
        //...
    }
}

對象文字具有在不污染全局命名空間的情況下幫助組織代碼和參數(shù)的優(yōu)點。如果我們希望創(chuàng)建易讀的可以支持深度嵌套的結(jié)構(gòu),這將非常有用。與簡單的全局變量不同,對象文字也經(jīng)??紤]測試相同名字的變量的存在,這樣就極大的降低了沖突的可能性。

下面例子中,我們展示了幾種方法,它們檢查是否變量(對象或者插件命名空間)存在,如果不存在就定義該變量。

// This doesn't check for existence of "myApplication" in
// the global namespace. Bad practice as we can easily
// clobber an existing variable/namespace with the same name
var myApplication = {};

// The following options *do* check for variable/namespace existence.
// If already defined, we use that instance, otherwise we assign a new
// object literal to myApplication.
//
// Option 1: var myApplication = myApplication || {};
// Option 2  if( !MyApplication ){ MyApplication = {} };
// Option 3: window.myApplication || ( window.myApplication = {} );
// Option 4: var myApplication = $.fn.myApplication = function() {};
// Option 5: var myApplication = myApplication === undefined ? {} : myApplication;

我們經(jīng)??吹介_發(fā)人員使用Option1或者Option2,它們都很容易理解,而且他們的結(jié)果也是一樣的。 Option 3 假定我們在全局命名空間中,但也可以寫成下面的方式:

myApplication || (myApplication = {});

這種改變假定myApplication已經(jīng)被初始化,所以它只對參數(shù)有效,如下:

function foo() {
  myApplication || ( myApplication = {} );
}

// myApplication hasn't been initialized,
// so foo() throws a ReferenceError

foo();

// However accepting myApplication as an
// argument

function foo( myApplication ) {
  myApplication || ( myApplication = {} );
}

foo();

// Even if myApplication === undefined, there is no error
// and myApplication gets set to {} correctly

Options 4 對于寫jQuery插件很有效:

// If we were to define a new plugin..
var myPlugin = $.fn.myPlugin = function() { ... };

// Then later rather than having to type:
$.fn.myPlugin.defaults = {};

// We can do:
myPlugin.defaults = {};

這樣的結(jié)果是代碼壓縮(最小化)效果好,而且可以節(jié)省查找范圍。

Option 5 跟Option 4有些類似,但它是一個較長的形式,它用內(nèi)聯(lián)的方式驗證myApplication是否未定義,如果未定義就將它定義為一個對象,否則就把已經(jīng)定義的值賦給myApplication。

Option 5的展示是為了完整透徹起見,但在大多數(shù)情況下Option 1-4就足夠滿足大多數(shù)需求了。

當然,在使用對象文字實習組織代碼結(jié)構(gòu)方面有很多變體. 對于希望為一個內(nèi)部封閉的模塊暴漏一個嵌套的API的小應(yīng)用來說,我們會發(fā)現(xiàn)自己使用“展示模塊模式”, 這個模式之前在本書中講過:

var namespace = (function () {

    // defined within the local scope
    var privateMethod1 = function () { /* ... */ },
        privateMethod2 = function () { /* ... */ }
        privateProperty1 = "foobar";

    return {

        // the object literal returned here can have as many
        // nested depths as we wish, however as mentioned,
        // this way of doing things works best for smaller,
        // limited-scope applications in my personal opinion
        publicMethod1: privateMethod1,

        // nested namespace with public properties
        properties:{
            publicProperty1: privateProperty1
        },

        // another tested namespace
        utils:{
            publicMethod2: privateMethod2
        }
        ...
    }
})();

對象文字的好處就是他們?yōu)槲覀兲峁┝艘环N非常優(yōu)雅的Key/Value語法,使用它,我們可以很容易的封裝我們應(yīng)用中任意獨特的邏輯,而且能夠清楚的將它與其他代碼區(qū)分開,同時它為代碼擴展提供了堅實的基礎(chǔ)。

一個可能的弊端就是,對象文字可能會導(dǎo)致很長的語法結(jié)構(gòu),你可以選擇利用嵌套命名空間模式(它也使用了同樣的模式作為基礎(chǔ))

這種模式也有很多有用的應(yīng)用。除了命名空間,它也被用來把應(yīng)用的默認配置縮減到一個獨立的區(qū)域中,這樣一來就修改配置就不需要查遍整個代碼庫了,對象文字在這方面表現(xiàn)非常好。下面的例子是一個假想的配置:

var myConfig = {

    language: "english",

    defaults: {
        enableGeolocation: true,
        enableSharing: false,
        maxPhotos: 20
    },

    theme: {
        skin: "a",
        toolbars: {
            index: "ui-navigation-toolbar",
            pages: "ui-custom-toolbar"   
        }
    }

}

注意:JSON是對象文字表示的一個子集,它與上面的例子(比如:JSON的鍵必須是字符串)只有細微的語法差異。如果出于某種原因,有人想使用JSON來存儲配置信息(比如:當發(fā)送到前端的時候),也是可以的。想了解更多關(guān)于對象文字表示模式,我建議閱讀Rebecca Murphey 的優(yōu)秀文章 ,她講到了很多我們上面沒有提到的問題。

嵌套命名空間

文字對象表示的一個擴展就是嵌套命名空間.它也是一個常用的模式,它降低了代碼沖突的可能,即使某個命名空間已經(jīng)存在,它嵌套的命名空間沖突的可能性卻很小。

下面的代碼看起來熟悉嗎?

YAHOO.util.Dom.getElementsByClassName("test");

Yahoo!'s YUI 庫經(jīng)常使用嵌套命名空間模式, 當我在AOL當工程師的時候,我們在很多大型應(yīng)用中也使用過這種模式。下面是嵌套命名空間的一個簡單的實現(xiàn):

var myApp =  myApp || {};

// perform a similar existence check when defining nested
// children
myApp.routers = myApp.routers || {};
myApp.model = myApp.model || {};
myApp.model.special = myApp.model.special || {};

// nested namespaces can be as complex as required:
// myApp.utilities.charting.html5.plotGraph(/*..*/);
// myApp.modules.financePlanner.getSummary();
// myApp.services.social.facebook.realtimeStream.getLatest();

注意: 上面的代碼與YUI3實現(xiàn)命名空間是不同的。上面的模塊使用沙盒API來保存對象,而且使用了更少、更短的命名空間。

我們也可以像下面一樣,選擇使用索引屬性來定義新的嵌套命名空間/屬性:

myApp["routers"] = myApp["routers"] || {};
myApp["models"] = myApp["models"] || {};
myApp["controllers"] = myApp["controllers"] || {};

兩種選擇可讀性都很強,而且很有條理,它們都提供了與我們可能在其他語言中使用的類似的一種相對安全的方式來給我們的應(yīng)用添加命名空間.唯一需要注意的是,這需要我們?yōu)g覽器中的JavaScript引擎首先定位到myApp對象,然后深入挖掘,直到找到我們想使用的方法為止。

這就以為著在查找方面會增加很多工作,然后開發(fā)人員比如Juriy Zaytsev 以前就做過測試,而且發(fā)現(xiàn)單個對象命名空間與嵌套命名空間在性能方面的差異是可以忽略不計的。

即時調(diào)用的函數(shù)表達式(IIFE)s

早在本書中,我們就簡單的介紹過IIFE (即時調(diào)用的函數(shù)表達式) ,它是一個未命名的函數(shù),在它被定義之后就會立即執(zhí)行。如果聽起來覺得耳熟,是因為你以前遇到過并將它稱之為自動生效的(或者自動調(diào)用的)匿名函數(shù),然而我個人更認為 Ben Alman的 IIFE 命名更準確。在JavaScript中,因為在一個作用域中顯示定義的變量和函數(shù)只能在作用域中可見,函數(shù)調(diào)用為實現(xiàn)隱私提供了簡單的方式。

IIFEs 將應(yīng)用邏輯封裝從而將它在全局命名空間中保護起來,但可以在命名空間范圍內(nèi)使用。

下面是IIFEs的例子:

// an (anonymous) immediately-invoked function expression
(function () { /*...*/})();

// a named immediately-invoked function expression
(function foobar () { /*..*/}());

// this is technically a self-executing function which is quite different
function foobar () { foobar(); }

對于第一個例子稍微進行一下擴展:

var namespace = namespace || {};

// here a namespace object is passed as a function
// parameter, where we assign public methods and
// properties to it
(function( o ){   
    o.foo = "foo";
    o.bar = function(){
        return "bar";   
    };
})( namespace );

console.log( namespace );

雖然可讀,這個例子可以被更大范圍的擴展到說明通用的開發(fā)問題,例如定義隱私的級別(public/private函數(shù)和變量),以及方便的命名空間擴展。我們來瀏覽更多的代碼:

// namespace (our namespace name) and undefined are passed here
// to ensure 1. namespace can be modified locally and isn't
// overwritten outside of our function context
// 2. the value of undefined is guaranteed as being truly
// undefined. This is to avoid issues with undefined being
// mutable pre-ES5.

;(function ( namespace, undefined ) {

    // private properties
    var foo = "foo",
        bar = "bar";

    // public methods and properties
    namespace.foobar = "foobar";
    namespace.sayHello = function () {
        speak( "hello world" );
    };

    // private method
    function speak(msg) {
        console.log( "You said: " + msg );
    };

    // check to evaluate whether "namespace" exists in the
    // global namespace - if not, assign window.namespace an
    // object literal

}( window.namespace = window.namespace || {} ));

// we can then test our properties and methods as follows

// public

// Outputs: foobar
console.log( namespace.foobar );

// Outputs: hello world
namescpace.sayHello();

// assigning new properties
namespace.foobar2 = "foobar";

// Outputs: foobar
console.log( namespace.foobar2 );

對任何可擴展的命名空間模式,可擴展性當然是關(guān)鍵,可以通過使用IIFEs很容易的達到這個目標。在下面的例子中,我們的"namespace"再次被當作參數(shù)傳遞給匿名函數(shù),之后擴展(或裝飾)了更多的功能:

// let's extend the namespace with new functionality
(function( namespace, undefined ){

    // public method
    namespace.sayGoodbye = function () {
        console.log( namespace.foo );
        console.log( namespace.bar );
        speak( "goodbye" );
    }   
}( window.namespace = window.namespace || {});

// Outputs: goodbye
namespace.sayGoodbye();

命名空間注入

命名空間注入是關(guān)于IIFE的另外一種變種,為了一個來自函數(shù)封裝中使用this作為命名空間代理的特定的命名空間,我們將方法和屬性“注入”, 這一模式提供的好處就是對于多個對象或者命名空間的應(yīng)用程序的功能性行為的便利性,并且在應(yīng)用一堆晚些時候?qū)⒈粯?gòu)建的基礎(chǔ)方法(如getter和setter),這將會變得很有用處。

這一模式的缺點就是,如我在本節(jié)前面所述,也許還會有達成此目的更加簡單并且更加優(yōu)化的方法存在(如,深度對象擴展/混合)。

下面我們馬上可以看到這一模式的一個示例,我們使用它來填充兩個命名空間的行為:一個最開始就定義(utils),而另外一個我們則將其作為utils的功能性賦值的一部分來動態(tài)創(chuàng)建(一個稱作tools的新的命名空間)。

var myApp = myApp || {};
myApp.utils =  {};

(function () {
  var val = 5;

  this.getValue = function () {
      return val;
  };

  this.setValue = function( newVal ) {
      val = newVal;
  }

  // also introduce a new sub-namespace
  this.tools = {};

}).apply( myApp.utils ); 

// inject new behaviour into the tools namespace
// which we defined via the utilities module

(function () {
    this.diagnose = function(){
        return "diagnosis";  
    }
}).apply( myApp.utils.tools );

// note, this same approach to extension could be applied
// to a regular IIFE, by just passing in the context as
// an argument and modifying the context rather than just
// "this"

// Usage:

// Outputs our populated namespace
console.log( myApp );

// Outputs: 5
console.log( myApp.utils.getValue() );

// Sets the value of `val` and returns it
myApp.utils.setValue( 25 );
console.log( myApp.utils.getValue() );

// Testing another level down
console.log( myApp.utils.tools.diagnose() );

Angus Croll先前也出過使用調(diào)用API來提供上下文環(huán)境和參數(shù)之間自然分離的主意。這一模式感覺上像是一個模塊創(chuàng)建器,但是由于模塊仍然提供了一個封裝的解決方案, 為全面起見,我們還是將簡要的介紹一下它:

// define a namespace we can use later
var ns = ns || {},
    ns2 = ns2 || {};

// the module/namespace creator
var creator = function( val ){

    var val = val || 0;

    this.next = function () {
        return val++
    };

    this.reset = function () {
        val = 0;
    }
}

creator.call( ns );

// ns.next, ns.reset now exist
creator.call( ns2 , 5000 );

// ns2 contains the same methods
// but has an overridden value for val
// of 5000

如前所述,這種類型的模式對于將一個類似的功能的基礎(chǔ)集合分派給多個模塊或者命名空間是非常有用的。然而我會只建議將它使用在要在一個對象/閉包中明確聲明功能,而直接訪問并沒有任何意義的地方。

高級命名空間模式

接下來說說我在開發(fā)大型應(yīng)用過程中發(fā)現(xiàn)的幾種有用的模式和工具,其中一些需要我們重新審視傳統(tǒng)應(yīng)用的命名空間的使用方式.需要注意的是,我并非有意夸大以下幾種是正確的命名空間之路,只是我在工作中發(fā)現(xiàn)他們確實好用。

自動嵌套命名空間

我們提到過,嵌套命名空間可以為代碼提供一個組織良好的層級結(jié)構(gòu).下邊是一個例子:application.utilities.drawing.canvas.2d . 可以用文字對象模式展開如下:

var application = {
      utilities:{
          drawing:{
              canvas:{
                  2d:{
                          //...
                  }
              }
          }
    }       
};

使用這種模式會遇到一些問題,一個顯而易見的就是每天加一個層級,就需要我們在頂級命名空間下的某個父級元素里定義一個額外的對象.當應(yīng)用越來越復(fù)雜的時候,我們需要的層級增多,解決這個問題也就更加困難。

怎樣更好的解決這個問題呢? 在JavaScript設(shè)計模式中, Stoyan Stefanov 提出了一個非常精巧的方法以便在已存在的全局變量下定義嵌套的命名空間。 他建議的簡便方法是為每一層嵌套提供一個單字符聲明,解析這個聲明就可以自動算出包含必要對象的命名空間。

我(筆者)將他建議使用的方法改進為一個通用方法,以便對多重命名空間更容易地做出復(fù)用,方法如下:

// 頂級命名空間賦值為對象字面量
var myApp = myApp || {};

// 解析字符命名空間并自動生成嵌套命名空間的快捷方法 function extend( ns, ns_string ) {
    var parts = ns_string.split("."),
        parent = ns,
        pl;

    pl = parts.length;

    for ( var i = 0; i < pl; i++ ) {
        // create a property if it doesn't exist
        if ( typeof parent[parts[i]] === "undefined" ) {
            parent[parts[i]] = {};
        }

        parent = parent[parts[i]];
    }

    return parent;
}

// 用法:
// extend為myApp加入深度嵌套的命名空間
var mod = extend(myApp, "modules.module2");

// 輸出深度嵌套的正確對象
console.log(mod);

// 用于檢查mod的實例作為包含擴展的一個實體也能夠被myApp命名空間以外被使用的少量測試

// 輸出: true
console.log(mod == myApp.modules.module2);

// 進一步演示用extend賦予嵌套命名空間更簡單
extend(myApp, "moduleA.moduleB.moduleC.moduleD");
extend(myApp, "longer.version.looks.like.this");
console.log(myApp);

Web審查工具輸出:

http://wiki.jikexueyuan.com/project/javascript-design-patterns/images/Fmos.png" alt="" />

一行簡潔的代碼就可以很輕松地,為他們的命名空間像以前的對象那樣明確聲明各種各樣的嵌套。

依賴聲明模式

現(xiàn)在我們將探索一種對嵌套命名空間模式的一種輕微的增強,它將被我們引申為依賴聲明模式。我們都知道對于對象的本地引用能夠降低全局查找的時間,但讓我們來將它應(yīng)用在命名空間中,看看實踐中它表現(xiàn)怎么樣:

// common approach to accessing nested namespaces
myApp.utilities.math.fibonacci( 25 );
myApp.utilities.math.sin( 56 );
myApp.utilities.drawing.plot( 98,50,60 );

// with local/cached references
var utils = myApp.utilities,
maths = utils.math,
drawing = utils.drawing;

// easier to access the namespace
maths.fibonacci( 25 );
maths.sin( 56 );
drawing.plot( 98, 50,60 );

// note that the above is particularly performant when
// compared to hundreds or thousands of calls to nested
// namespaces vs. a local reference to the namespace

這里使用一個本地變量相比頂層上一個全局的(如,myApp)幾乎總是會更快。相比訪問其后每行嵌套的屬性/命名空間,這也更加的方便,性能表現(xiàn)更好,并且能夠在更加復(fù)雜的應(yīng)用程序場景下面提升可讀性。

Stoyan建議在我們的函數(shù)范圍(使用單變量模式)的頂部聲明函數(shù)或者模塊需要的局部命名空間,并把這稱為依賴聲明模式。其中的一個好處是減少了定位和重定向依賴關(guān)系的時間,從而使我們有一個可擴展的架構(gòu),當需要時可以在命名空間里動態(tài)地加載模塊。

在我看來,這種方式應(yīng)用于模塊化級別時,將被其他方法使用的命名空間局部化是最有效。我建議盡量避免把命名空間局部化在單個函數(shù)級別,尤其是對于命名空間的依賴關(guān)系上有明顯的重疊的情況。對應(yīng)的方法是,在上部定義并使它們可以進入同一個引用。

深度對象擴展

另一種實現(xiàn)自動命名空間的方式就是深度對象擴展. 使用對象文字表示的命名空間可以很容易地與其他對象(或命名空間)擴展(或者合并) 這樣兩個命名空間下的屬性和方法就可以在同一個合并后的命名空間下被訪問。

一些現(xiàn)代的JavaScript框架已經(jīng)把這個變得非常容易(例如,jQuery的$.extend),然而,如果你想尋找一種使用普通的JS來擴展對象(命名空間)的方式,下面的內(nèi)容將很有幫助。

// extend.js
// Written by Andrew Dupont, optimized by Addy Osmani

function extend( destination, source ) {

    var toString = Object.prototype.toString,
        objTest = toString.call({});

    for ( var property in source ) {
        if ( source[property] && objTest === toString.call(source[property]) ) {
            destination[property] = destination[property] || {};
            extend(destination[property], source[property]);
        } else {
            destination[property] = source[property];
        }
    }
    return destination;

};

console.group( "objExtend namespacing tests" );

// define a top-level namespace for usage
var myNS = myNS || {};

// 1. extend namespace with a "utils" object
extend(myNS, {
        utils:{
        }
});

console.log( "test 1" , myNS);
// myNS.utils now exists

// 2. extend with multiple depths (namespace.hello.world.wave)
extend(myNS, {
                hello:{
                        world:{
                                wave:{
                                    test: function(){
                                        //...
                                    }
                                }
                        }
                }
});

// test direct assignment works as expected
myNS.hello.test1 = "this is a test";
myNS.hello.world.test2 = "this is another test";
console.log( "test 2", myNS );

// 3. what if myNS already contains the namespace being added
// (e.g. "library")? we want to ensure no namespaces are being
// overwritten during extension

myNS.library = {
        foo:function () {}
};

extend( myNS, {
        library:{
                bar:function(){
                    //...
                }
        }
});

// confirmed that extend is operating safely (as expected)
// myNS now also contains library.foo, library.bar
console.log( "test 3", myNS );

// 4. what if we wanted easier access to a specific namespace without having
// to type the whole namespace out each time?

var shorterAccess1 = myNS.hello.world;
shorterAccess1.test3 = "hello again";
console.log( "test 4", myNS);

//success, myApp.hello.world.test3 is now "hello again"

console.groupEnd();

注意: 上面的實現(xiàn)對于所有的對象來說不是跨瀏覽器的而且只應(yīng)該被認為是一個概念上的證明. 你可能會覺得前面帶下劃線的js.extend()方法更簡單一些,下面的鏈接提供了更多的跨瀏覽器實現(xiàn),http://documentcloud.github.com/underscore/docs/underscore.html#section-67。 另外,從代碼中抽取出來的jQuery $.extend() 方法可以在這里找到: https://github.com/addyosmani/jquery.parts。 對于那些將使用jQuery的開發(fā)者來說, 可以像下面一樣使用$.extend來達到同樣的對象命名空間擴展的目的:

// top-level namespace
var myApp = myApp || {};

// directly assign a nested namespace
myApp.library = {
  foo:function(){
    //...
  }
};

// deep extend/merge this namespace with another
// to make things interesting, let's say it's a namespace
// with the same name but with a different function
// signature: $.extend( deep, target, object1, object2 )
$.extend( true, myApp, {
    library:{
        bar:function(){
            //...
        }
    }
});

console.log("test", myApp);
// myApp now contains both library.foo() and library.bar() methods
// nothing has been overwritten which is what we're hoping for.

為了透徹起見,請點擊這里 來查看jQuery $.extend來獲取跟這一節(jié)中其它實現(xiàn)命名空間的過程類似的功能。

建議

回顧我們在本部分探討的命名空間模式,對于大多數(shù)更大的應(yīng)用程序,我個人則是選擇嵌入用對象字面值模式為命名空間的對象。我盡可能地用自動嵌入命名空間,當然這只是個人偏好罷了。

IIFEs 和單個全局變量可能只在中小規(guī)模的應(yīng)用程序中運轉(zhuǎn)良好。然而,更大的需要命名空間和深度子命名空間的代碼庫則需要一個簡明的,能提高可讀性和規(guī)模的解決方案。我認為是這種模式很好地達到了這些目標。我同樣推薦你嘗試一些拓展命名空間的高級實用的方法,因為它們能長期地節(jié)省我們的時間。

上一篇:暴露模塊模式下一篇:原型模式