深刻理解模塊化編程

1.模塊化開發規範

JavaScript中全部對象的屬性都是公共的,並無什麼明確的方法來代表屬性可否從對象的外部被訪問,而有時候咱們並不但願對象的屬性被外界訪問。一種方式方式經過命名約定的形式,好比在變量的前面加下劃線(_)。還有一些其餘的方式是屬性徹底私有化。javascript

2.爲何要模塊化

在模塊化沒有出現以前,咱們JavaScript腳本大概是這樣的:html

<script src="module1.js"></script>
    <script src="module2.js"></script>
    <script src="module3.js"></script>
    <script src="module4.js"></script>
    ....

但咱們引入多個js文件時,會存在一些問題:前端

  • 把全部的代碼放到全局環境會引發衝突
  • 各個腳本必須按照嚴格的依賴順序放置
  • 在大型的項目中,可能會引入不少的js腳本,script就會變得不少,而且難以維護。

爲了解決這些問題,涌現了各類模塊化的方案。java

3.模塊化的方式

這種方式是建立對象的一種方法,用於建立具備私有屬性的對象。基本思路是使用一個當即執行的函數表達式,返回一個對象。該函數表達式能夠包含任意數量的局部變量,這些變量從函數的外部是沒法訪問到的。由於返回的對象是在自執行函數內部聲明的,因此對象中定義的方法能夠訪問自執行函數內的局部變量,這些方法被具備特權的方法。node

 var p2 = (function(){

            var money = 30000;

            return {
                name: 'lisi',
                sayMoney: function(){
                    return money;
                }
            };

        }());

4. CommonJS

咱們在前端的js代碼在沒有模塊化以前也能正常執行,可是在服務器端的js腳本必需要被模塊化才能正常工做。因此雖然JavaScript在前端發展了這麼多年,第一個流行的模塊化規範倒是由服務器端的js應用發展起來的。CommonJS規範是由NodeJS發揚光大的。數組

  1. 定義模塊

在CommonJS規範中,一個單獨的JS文件就是一個模塊。每一個模塊都是一個單獨的做用域,也就是說,在該模塊內部定義的變量,沒法被其餘模塊讀取,除非定義爲global對象的屬性。瀏覽器

  1. 模塊輸出

模塊只有一個出口,module.exports對象,咱們須要把須要輸出的內容放入該模塊服務器

  1. 加載模塊

加載模塊使用require()方法,該方法讀取一個文件並執行,返回文件內部的module.exprots對象異步

例如,咱們寫了這樣一個文件myModule1.js模塊化

var name = '無忌';
function sayName(){
    console.log(name);
};

function sayFullName(firstName){
    console.log(firstName + name);
};
module.exports = {
    printName:sayName,
    printFullName:sayFullName
};

咱們的模塊定義好了,那咱們怎樣使用這個模塊呢?例如,咱們建立了myModule2.js文件:

var module1 = require('./myModule1.js');

module1.printName();
module1.printFullName('張');

在node環境下,require方法在引入其餘模塊的時候是同步的,能夠輕鬆的控制模塊的引入順序,保證了模塊之間的依賴順序。可是在瀏覽器中卻不是這樣的,由於咱們的<script>標籤天生異步,在加載js文件的時候是異步的,也就意味着不能保證模塊之間的正確依賴。

5. AMD規範

AMD即Asynchronous Module Definition,異步模塊定義。它是在瀏覽器端實現模塊化開發的規範。因爲該規範不是JavaScript原始支持的,使用AMD規範進行開發的時候須要引入第三方的庫函數,也就是鼎鼎大名的RequireJS

RequireJS主要解決兩個問題:

  1. 多個js文件可能有依賴關係,被依賴的文件須要早於依賴它的文件加載到瀏覽器。
  2. js加載的時候瀏覽器會中止頁面渲染,加載的文件越多,頁面失去響應的時間越長。

  3. 定義模塊

RequireJS定義了一個define函數,用來定模塊。

define(id, [dependencies], factory);

  • id:可選參數,用來定義模塊的標識,若是沒有提供參數的話,默認爲文件的名字。
  • dependencies:當前模塊依賴的其餘模塊,數組。
  • factory:工廠方法,初始化模塊須要執行的函數或對象。若是爲函數,它只被執行一次。若是是對象,此對象會做爲模塊的輸出值。
// amdModule1.js

define('amdModule1',[],function(){
    
    console.log('模塊一');
    
    var name= '張三';
    
    var money = 1000;
    
    var sayName = function(){
        return name;
    }
    var sayMoney = function(){
        return money;
    }
    return {
        sayName:sayName,
        sayMoney:sayMoney
    }
})

// module2.js


define('amdModule2',['amdModule1'],function(amdModule1){
    
    console.log('模塊二');
    
    var name = '李四';
    
    var weight = 80;
    
    var sayName = function(){
        return amdModule1.sayName();
    }
    var sayWeight = function(){
        return weight;
    }
    return {
        sayWeight:sayWeight,
        name:name,
        sayName:sayName
    };
})
  1. 在頁面中加載模塊

加載模塊須要使用require()函數。

require([dependencies], function(){});

  • dependencies:該參數是一個數組,表示所依賴的模塊。
  • function:這是一個回調函數,當所依賴的模塊都加載成功以後,將調用該回調方法。依賴的模塊會以參數的形式傳入該函數,從而在回調函數內部就可使用這些模塊。
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <script src="require.js"></script>
        <script type="text/javascript" src="amdModule1.js"></script>
        <script type="text/javascript" src="amdModule2.js"></script>
        <script type="text/javascript">
            require(['amdModule1','amdModule2'],function(amdModule1,amdModule2){
                console.log(amdModule1.sayName());  //張三
                console.log(amdModule1.name); //undefined
                console.log(amdModule2.sayName()); //張三
                console.log(amdModule2.sayWeight()); //80
            });
        </script>
    </body>
</html>

require()函數在加載依賴的模塊時,是異步加載的,這樣瀏覽器就不會失去響應,回調函數只有在所依賴的所有模塊都被被成功加載以後才執行,所以,解決了依賴性的問題。

6. CMD規範

CMD即Common Module Definition通用模塊定義。它解決的問題和AMD規範是同樣的,只不過在模塊定義方式和模塊加載時機上不一樣。CMD也須要額外的引入第三方的庫文件,SeaJS。

SeaJS推崇一個模塊一個文件,遵循統一的寫法:

define(id, dependencies, factory);

由於CMD推崇一個文件一個模塊,因此常用文件名做爲模塊的ID;CMD推崇就近原則,因此通常再也不define的參數中寫依賴,在factory函數中寫。

  • require:咱們定義的模塊可能會依賴其餘模塊,這個時候就可以使用require()引入依賴。
  • exports:等價於module.exports,只是爲了方便咱們使用
  • module.exports:用於存放模塊須要暴露的屬性
  1. 定義模塊
// cmdModule1.js

define(function(require,exports,module){
    var name = '張三';
    function sayName(){
        return name;
    }
    module.exports={
        sayName:sayName
    }
})

// cmdModule2.js


define(function(require,exports,module){
    
    var cmdModule1 = require('cmdModule1.js');
    console.log('模塊');
    function sayName(){
        return cmdModule1.sayName();
    }
    module.exports={
        sayName:sayName
    }
})
  1. 使用模塊
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <script src="sea.js"></script>
        <script src="cmdModule2.js"></script>
        <script src="cmdModule1.js"></script>
        <script type="text/javascript">
            seajs.use(['cmdModule2.js','cmdModule1.js'],function(cmdModule2,cmdModule1){
                console.log(cmdModule2.sayName());
                console.log(cmdModule1.sayName());
            })
        </script>
    </body>
</html>

7. AMD和CMD規範的區別

AMD在加載模塊完成後會當即執行該模塊,全部的模塊都加載完成後執行require方法中的回調函數,執行主邏輯,這樣的效果就是依賴模塊的執行順序和書寫順序不必定一致,看網速,誰先下載下來,誰先執行,可是咱們的主邏輯必定是在全部的依賴模塊都被加載完成後才執行。

CMD加載完某個模塊的時候並不執行,只是把它們下載下來而已,在全部的模塊下載完成後,當使用require請求某個模塊的時候,才執行對應的模塊。

相關文章
相關標籤/搜索