JavaScript設(shè)計模式(2)——Module(模塊)模式

JavaScript中的模塊實現(xiàn)方法有:

  • 對象字面量(本篇介紹)
  • Module模式(下篇介紹)
  • AMD模塊(無)
  • CommonJS模塊(無)
  • ECMAScript Harmony模塊(無)

模塊通常用來分離和組織項目中的代碼單元。

1. 對象字面量

對象字面量表示法中,一個對象被描述為一組包含在大括號({})中,以逗號分割的name/value對。
對象內(nèi)的名稱可以是字符串或者標(biāo)識符,用冒號結(jié)尾。
最后一個name/value對后面不能加逗號。

var myObjectLiteral = {
    variableKey:variableValue,
    functionKey:function(){
        //...
    }
};

對象字面量不需要使用new關(guān)鍵字來進行實例化。
使用對象字面量表示的模塊示例:

var myModule = {
    // 對象字面量可以擁有屬性
    myProperty : "someValue",

    // 對象字面量可以包含對象
    myConfig : {
        useCaching: true,
        language: "en"
    }

    // 可以擁有方法
    myMethod : function(){
        console.log("this is a message from a method in mosule");
    }

    // 根據(jù)當(dāng)前配置輸出信息
    myMethod2 : function(){
        console.log("Caching is: " + this.myConfig.useCaching ? "enabled" : "disabled");
    }

    // 重寫當(dāng)前配置
    myMethod3 : function(newConfig){
        if(typeof newConfig === "object"){
            this.myConfig = newConfig;
            console.log(this.myConfig.language);
        }
    }
};

// 輸出this is a message from a method in mosule
myModule.myMethod();

// 輸出enable
myModule.myMethod2();

// 輸出cn
myModule.myMethod3({
    language: "cn",
    useCaching : false
});

2. Module(模塊)模式

JavaScript中,Mosule模式用于模擬類的概念,這種方式能夠使一個單獨的對象擁有公有/私有方法和變量,從而屏蔽來自全局作用域的特殊部分。
可以使得函數(shù)名于頁面其他腳本定義的函數(shù)沖突的可能性降低。

2.1 私有

JavaScript中沒有真正意義上的私有,因為它沒有訪問修飾符。因此需要使用函數(shù)作用域來模擬這一概念。
Module模式使用閉包封裝“私有”狀態(tài)和組織,它提供了一種包裝混合私有/公有的方法和變量的表達式,防止其泄露到全局作用域。
通過閉包,暴露一個公有API,其他的部分維持在私有閉包中。

2.2 示例

  1. 自包含的模塊實現(xiàn)Module模式
var testModule = (function(){
    var counter = 0;
    return {
        incrementCounter: function(){
            return ++counter;
        },

        resetCounter: function(){
            console.log("counter value prior to reset: "+ counter);
            counter = 0;
        }
    };
})();

// 用法:

//增加計數(shù)器
testModule.incrementCounter();

// 檢查計數(shù)器并重置
// 輸出:counter value prior to reset: 1
testModule.resetCounter();

// 輸出:undefined
console.log(testModule.counter);

在這里,代碼外部無法直接讀取incrementCounter()或者resetCounter()。也無法訪問其中的counter變量,這樣它表現(xiàn)的就像一個私有變量。

  1. 一個包含命名空間,公有和私有變量的Module模式
var myNameSpace = (function(){
    // 私有計數(shù)器變量
    var myPrivateVar = 0;

    // 記錄所有參數(shù)的私有函數(shù)
    var myPrivateMethod = function(foo){
        console.log(foo);
    };

    return {
        //公有變量
        myPublicVar : "foo",
        myPublicFunction : function(bar){
            // 私有變量自增
            myPrivateVar++;

            // 傳入bar調(diào)用私有方法
            myPrivateMethod(bar);
        }
    };
})();

在這些例子中,模塊中的作用域函數(shù)包裹在所有的函數(shù)周圍,然后調(diào)用并立即存儲返回值,這樣有很多優(yōu)點,包括:

  • 只有該模塊才有使用私有函數(shù)的自由,因為這些函數(shù)不會暴露在頁面的其他部分,暴露出來只有輸出的API
  • 鑒于函數(shù)往往函數(shù)已經(jīng)聲明并命名,在試圖找到函數(shù)拋出的異常時,這將使調(diào)制器中顯示調(diào)用堆棧顯得容易
  • 根據(jù)環(huán)境,可以返回不同的函數(shù)

3. 模式變化

3.1 引入混入

下面的例子演示了全局變量(jQuery,Underscore)如何作為參數(shù)傳遞給模塊的匿名函數(shù)。我們引入它們,并給它們?nèi)∫粋€本地別名。

// 全局模塊
var myModule = (function(jQ, _){
    function privateMethod1(){
        jQ(".container").html("test");
    }

    function provateMethod2(){
        console.log(_.min([10, 5, 100, 2, 1000]}));
    }

    return {
        publicMethod: function(){
            privateMethod1();
        }
    };
    // 引入jQuery和Uderscore
})(jQuery, _);

myModule.publicMethod();

3.2 引出

下面的例子聲明了一個全局變量,而不需要實現(xiàn)它們,并可以同樣地作為全局變量引入到模塊中。

// 全局模塊
var myModule = (function(){
    // 模塊對象
    var module = {},

    // 私有屬性
    var privateVariable = "asd";

    //私有方法
    function provateMethod(){
        // ...
    }

    module.publicProperty = "FooBar";
    module.publicMethod = function(){
        console.log(privateVariable);
    }
    return module;
})();

3.3 特定框架下的Module模式實現(xiàn)

這里僅介紹jQuery下Module模式的實現(xiàn),示例中定義了library函數(shù),聲明一個新庫,并在創(chuàng)建新庫時將init函數(shù)自動綁定到document.ready。

function library(module){
    $(function(){
        if(module.init()){
            module.init();
        }
    });
    return module;
}

var myLibrary = library(function(){
    return {
        init:function(){
            // module implementation
            // 模塊實現(xiàn)
        }
    };
})();

3.4 優(yōu)點

首先,對于面向?qū)ο髞碚f,比起真正的封裝思想,從JavaScript的角度而言是很簡潔的。
其次,它支持了私有數(shù)據(jù)

3.5 缺點

由于我們訪問私有和公有成員的方法不同,當(dāng)我們想改變可見性時,實際上我們要修改每一個使用過成員變量的地方。
此外,我們也無法訪問那些在方法里添加的私有成員。
其他缺點包括:

  • 無法為私有成員創(chuàng)建自動化單元測試,bug需要增加補丁時會增加額外的復(fù)雜性。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容