1. 程式人生 > >前端的模塊化編程

前端的模塊化編程

glob style 打包 ons 這樣的 對象 mode active 有用

對前端模塊化的認識
一個大型項目時候,通常需要一個團隊分工合作,模塊化編程就是開發者把邏輯相關的代碼放在一個module裏面,我們只需要實現核心的業務邏輯,
不用擔心命名沖突,需要時再加載就可以。
Javascript不是一種模塊化編程語言,開發者需要模擬出類似的功能,來將一個大程序拆分成相互依賴的小文件,我們稱為模塊化。
有了模塊,我們就可以更方便地使用別人的代碼,想要什麽功能,就加載什麽模塊。

早期模塊化編程的方法

1)函數
最早期,我們的函數的功能就是把實現特定邏輯的一組語句打包,在一個文件裏面編寫幾個函數就是最開始的模塊了

這樣在使用的時候直接調用函數就可以了,但是這種做法有一個很大的缺點,就是汙染了全局變量,很有可能早造成命名沖突,而且模塊成員之間也沒什麽關系

function fn1(){
    statement
}
function fn2(){
    statement
}

2)對象
為了解決上面的問題,對象的寫法應運而生了,我們可以把所有的模塊成員封裝在一個對象當中。這樣我們在調用的時候只要引用對應的文件,然後調用對象的方法就可以,而且避免了全局變量汙染,只要保證模塊名唯一即可,而且模塊內的成員也有了關系,但是這個方法的缺點就是外部可以隨意修改內部成員

var mymodule{
    var1:1,
    var2:2,
    fn1:function(){},
    fn2:function(){}
}

3)立即執行函數
我們可以使用立即執行函數來達到隱藏細節的目的,這樣在模塊外部無法修改我們內部的變量和函數

var mymodule=(function(){
    var var1=1;
    var var2=2;
    function fn1(){};
    function fn2(){};
    return {
        fn1: fn1,
        fn2: fn2
    };
})();

以上三種做法就是我們模塊化的基礎

模塊化規範

因為有了模塊,我們就可以更方便地使用別人的代碼,想要什麽功能,就加載什麽模塊。
這樣做的前提就是大家都以同樣的方式來編寫模塊,那麽有一個模塊化的規範就非常重要
在ES6之前,JavaScript模塊規範主要有兩種:CommonJS和AMD,前者用於服務器,後者用於瀏覽器

CommonJS

commonJS是用於服務器端的模塊化規範,node.js的模塊系統,就是參照CommonJS規範實現的

1)定義模塊
根據CommonJS規範,一個單獨的文件就是一個模塊,並且每個模塊都是單獨的作用域,在該模塊內定義的變量無法被其他模塊讀取,除非定義為global對象的屬性
2)模塊輸出
模塊只有一個出口,module.exports對象,我們把模塊需要輸出的內容放入該對象
3)加載模塊
使用require方法,該方法用於讀取一個模塊並執行,返回模塊內部的module.exports對象

//模塊定義 myModel.js
var name = ‘Byron‘;
function printName(){
    console.log(name);
}
function printFullName(firstName){
    console.log(firstName + name);
}
//模塊輸出
module.exports = {
    printName: printName,
    printFullName: printFullName
}
//加載模塊
var nameModule = require(‘./myModel.js‘);
//調用模塊的方法
nameModule.printName();

AMD

AMD(異步模塊定義)是一個在瀏覽器端模塊化開發的規範,它采用異步方式加載模塊,模塊的加載不影響它後面語句的運行。也解決了模塊依賴性的問題。

requireJS定義了一個函數 define,它是全局變量,用來定義模塊

define(id?, dependencies?, factory);
  1. id:可選參數,用來定義模塊的標識
  2. dependencies:是一個當前模塊依賴的模塊名稱數組
  3. factory:工廠方法,模塊初始化要執行的函數或對象。如果為函數,它應該只被執行一次。如果是對象,此對象應該為模塊的輸出值

AMD也采用require()語句加載模塊,但是不同於CommonJS,它要求兩個參數:

require([module], callback);
  1. 第一個參數是一個數組,裏面的成員就是要加載的模塊
  2. 第二個參數callback,則是加載成功之後的回調函數。

所有依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成之後,這個回調函數才會運行。解決了依賴性的問題。

// 定義模塊 myModule.js
define([‘dependency‘], function(){
    var name = ‘Byron‘;
    function printName(){
        console.log(name);
    }

    return {
        printName: printName
    }
});
// 加載模塊
require([‘myModule‘], function (my){
    my.printName();
});

CMD

CMD(通用模塊定義)國內發展出來的,就像AMD有個requireJS,CMD有個SeaJS

eaJS要解決的問題和requireJS一樣,只不過在模塊定義方式和模塊加載時機上有所不同

MD推崇"依賴就近",所以一般不在define的參數中寫依賴,在factory中寫

define(id?, deps?, factory)

factory有三個參數

function(require, exports, module) 
  1. require 是 factory 函數的第一個參數,是一個方法,接受 模塊標識 作為唯一參數,用來獲取其他模塊提供的接口
  2. exports 是一個對象,用來向外提供模塊接口
  3. module 是一個對象,上面存儲了與當前模塊相關聯的一些屬性和方法
// 定義模塊  myModule.js
define(function(require, exports, module) {
  var $ = require(‘jquery.js‘)
  $(‘div‘).addClass(‘active‘);
});

// 加載模塊
seajs.use([‘myModule.js‘], function(my){

});

AMD與CMD區別:
最明顯的區別就是在模塊定義時對依賴的處理不同
  1)AMD推崇依賴前置,在定義模塊的時候就要聲明其依賴的模塊
  2)CMD推崇就近依賴,只有在用到某個模塊的時候再去require

同樣都是異步加載模塊
  1)AMD所有模塊都加載並且執行完後會進入require的回調函數,執行主邏輯,這樣的效果就是依賴模塊的執行順序和書寫順序不一定一致,看網絡速度,哪個先下載下來,哪個先執行,但是主邏輯一定在所有依賴加載完成後才執行
  2)CMD加載完某個依賴模塊後並不執行,只是下載而已,在所有依賴模塊加載完成後進入主邏輯,遇到require語句的時候才執行對應的模塊,這樣模塊的執行順序和書寫順序是完全一致的
這也是很多人說AMD用戶體驗好,因為沒有延遲,依賴模塊提前執行了;CMD性能好,因為只有用戶需要的時候才執行的原因

前端的模塊化編程