模塊化進(jìn)程——CommonJs、AMD、CMD、UMD

原因

javascript早期作為一門輕量級語言,用于在 Web 上與用戶進(jìn)行少量的交互,并沒有依賴管理的概念。但隨著ajax技術(shù)的發(fā)展,js被要求實(shí)現(xiàn)的功能越來越多。全局變量污染,依賴混亂等問題亟待解決。其他語言已經(jīng)實(shí)現(xiàn)的模塊化被提上日程。

前驅(qū)

在正式的模塊化方案發(fā)布之前,有人想了其他方法解決變量污染的問題

  1. 雅虎的開源組件庫 YUI Library
    采用了類似java命名空間的方式,但是因?yàn)檎{(diào)用和封裝都太過復(fù)雜并沒有推廣起來
YUI.util.module.doSomthing();
  1. JQuery
    運(yùn)用了閉包的特性,在加載之初執(zhí)行函數(shù),把JQuery變量掛載到全局的window對象上
(function(root){
  root.JQuery = root.$ = JQuery
})(window)

正式起航

1、CommonJS -- 最早的解決方案

1.1 背景
  1. mozilla 的工程師為解決用于服務(wù)端的js的自動化測試的模塊導(dǎo)入問題,制定了一套模塊化導(dǎo)入的規(guī)范,命名為ServerJS(Modules/0.1),這就是CommonJS的前身。
  2. 后來正式更名為CommonJS(Modules/1.0),從命名可以看出其野心,企圖一統(tǒng)所有編程語言的模塊化方案。
  3. Node的創(chuàng)始人決定為其包依賴管理尋找解決辦法時選擇了CommonJS的規(guī)范來,我覺得對其的推廣起到了極大的促進(jìn)作用。
1.2 具體實(shí)現(xiàn)
  1. 在CommonJS中一個文件就是一個模塊,擁有自己獨(dú)立的作用域,變量及方法;
  2. 定義全局變量require,通過在require中傳入唯一的標(biāo)識來引入文件的依賴模塊,其執(zhí)行結(jié)果就是模塊暴露的API;
  3. 如果執(zhí)行失敗,require會拋出一個錯誤;
  4. 模塊通過exports向外暴露API,導(dǎo)出的必須是一個object,暴露的API是該對象的屬性
//moudleA.js
moudle.exports = {
    a: 1
};
//moudleB.js
var ma = require('./moudleA');
var b = ma.a + 2;
module.exports ={
    b: b
};

分裂統(tǒng)一(AMD、CMD、UMD)

由于CommonJS是起源于服務(wù)端的,所以雖然說他是一門很好的模塊化解決辦法的實(shí)現(xiàn)方法,但是其并不能運(yùn)用于瀏覽器端。所以瀏覽器端需要新的實(shí)現(xiàn)方法。但是在實(shí)現(xiàn)方法上CommonJS內(nèi)部出現(xiàn)了分歧,從而誕生了AMD、CMD、UMD三種解決方法(當(dāng)然還有其他小眾的方法,因?yàn)槠涫褂萌藬?shù)較少這里不做討論)。

保守派 —— browserify

這一派的理念是不動CommonJS,為配合瀏覽器實(shí)現(xiàn),可以使用一些其他方法將其轉(zhuǎn)化成瀏覽器可以理解的方法。跟我們現(xiàn)在的Babel的實(shí)現(xiàn)思想是一樣的。browserify就是這一觀點(diǎn)下的產(chǎn)物。

激進(jìn)派—— AMD(RequireJS)

這一派的觀點(diǎn)是既然不適用了那就改,應(yīng)該依據(jù)瀏覽器的特點(diǎn)放棄require,改用回調(diào)方式。但是其觀點(diǎn)并沒有被CommonJS社區(qū)接受所以這一派最終脫離了CommonJS社區(qū)自立門戶,起初是專注于RequireJS的開發(fā),后來才起草了AMD 異步模塊定義規(guī)范(Async Module Definition)。

AMD 作為一個規(guī)范,只需定義其語法 API,而不關(guān)心其實(shí)現(xiàn)。AMD 規(guī)范簡單到只有一個 API,即 define 函數(shù):

 define(id?, dependencies?, factory);
  1. 定義全局函數(shù) define(id, dependencies, factory),用于定義模塊。dependencies 為依賴的模塊數(shù)組,在 factory 中需傳入形參與之一一對應(yīng)。
  2. 如果 dependencies 的值中有 require、exports 或module,則與 CommonJS 中的實(shí)現(xiàn)保持一致。
  3. 如果 dependencies 省略不寫,則默認(rèn)為 ['require', 'exports', 'module'],factory 中也會默認(rèn)傳入三者。
  4. 如果 factory 為函數(shù),模塊可以通過以下三種方式對外暴漏 API:return 任意類型;exports.XModule = XModule、module.exports = XModule。
  5. 如果 factory 為對象,則該對象即為模塊的導(dǎo)出值。

中間派——CMD、UMD

1. CMD

這一派認(rèn)為require不用放棄,但export也可以導(dǎo)出除object以外的其他類型。淘寶玉伯寫出了SeaJS,提出了CMD(Common Module Definition)規(guī)范,其在國內(nèi)很火,但并未在國外流行。

CMD 規(guī)范的主要內(nèi)容與 AMD 大致相同,不過保留了 CommonJS 中最重要的延遲加載、就近聲明(就近依賴)特性。

// moudleA.js
define(function(require, exports, module) {
  module.exports = { 
      a: 1 
  };
});
// moudleB.js
define(function(require, exports, module) {
  var ma = require('./moudleB');
  var b = ma.a + 2;
  module.exports = { 
      b: b 
  };
});
2. UMD

UMD 即 Universal Module Definition 的縮寫,它本質(zhì)上并不是一個真正的模塊化方案,而是將 CommonJS 和 AMD 相結(jié)合。

((root, factory) => {
    if (typeof define === 'function' && define.amd) {
        //AMD
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        //CommonJS
        var $ = requie('jquery');
        module.exports = factory($);
    } else {
        root.testModule = factory(root.jQuery);
    }
})(this, ($) => {
    //todo
});

正統(tǒng) —— ES6/ES2015

時間前進(jìn)到 2016 年 5 月,經(jīng)過了兩年的討論,ECMAScript 6.0 終于正式通過決議,成為了國際標(biāo)準(zhǔn)。

在這一標(biāo)準(zhǔn)中,首次引入了 importexport 兩個 JavaScript 關(guān)鍵字,并提供了被稱為 ES Module 的模塊化方案。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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