在學習js和使用js的過程中一定會使用到模塊化開發的思想。而提到模塊化就一定會提到CommenJS、RequireJS、AMD、CMD等名詞。下面我將根據自己查閱的資料梳理以下這幾個名詞背後的關聯。
首先上個圖,直觀的感受下這幾個名詞的關係:
amd, cmd是用在瀏覽器端的,這兩種規範規定的模塊的加載方式是異步的,它們的對應的模塊加載器分別是requirejs和seajs。
其中,amd先提出,cmd是根據commonjs和amd基礎上提出的。
CommonJs 是服務器端模塊的規範,Node.js採用了這個規範。
根據CommonJS規範,一個單獨的文件就是一個模塊。加載模塊使用require方法,該方法讀取一個文件並執行,最後返回文件內部的exports對象。
例如:
// foobar.js
//私有變量
var test = 123;
//公有方法
function foobar () {
this.foo = function () {
// do someing ...
}
this.bar = function () {
//do someing ...
}
}
//exports對象上的方法和變量是公有的
var foobar = new foobar();
exports.foobar = foobar;
//require方法默認讀取js文件,所以可以省略js後綴
var test = require('./boobar').foobar;
test.bar();
CommonJS加載模塊是同步的,所以只有加載完成才能執行後面的操作。像Node.js主要用於服務器的編程,加載的模塊文件一般都已經存在本地硬盤,所以加載起來比較快,不用考慮異步加載的方式,所以CommonJS規範比較適用。但如果是瀏覽器環境,要從服務器加載模塊,這時就需要採用異步模式。所以就有了 AMD 和CMD 解決方案。
AMD((Asynchromous Module Definition)
AMD 是 RequireJS 在推廣過程中對模塊定義的規範化產出
AMD異步加載模塊。它的模塊支持對象 函數 構造器 字符串 JSON等各種類型的模塊。
適用AMD規範適用define方法定義模塊。
//通過數組引入依賴 ,回調函數通過形參傳入依賴
define(['someModule1', ‘someModule2’], function (someModule1, someModule2) {
function foo () {
/// someing
someModule1.test();
}
return {foo: foo}
});
AMD規範允許輸出模塊兼容CommonJS規範,這時define方法如下:
define(function (require, exports, module) {
var reqModule = require("./someModule");
requModule.test();
exports.asplode = function () {
//someing
}
});
CMD
CMD是SeaJS 在推廣過程中對模塊定義的規範化產出
CMD和AMD的區別有以下幾點:
1.對於依賴的模塊AMD是提前執行,CMD是延遲執行。不過RequireJS從2.0開始,也改成可以延遲執行(根據寫法不同,處理方式不通過)。
2.CMD推崇依賴就近,AMD推崇依賴前置。
//AMD
define(['./a','./b'], function (a, b) {
//依賴一開始就寫好
a.test();
b.test();
});
//CMD
define(function (requie, exports, module) {
//依賴可以就近書寫
var a = require('./a');
a.test();
...
//軟依賴
if (status) {
var b = requie('./b');
b.test();
}
});
雖然 AMD也支持CMD寫法,但依賴前置是官方文檔的默認模塊定義寫法。
3.AMD的api默認是一個當多個用,CMD嚴格的區分推崇職責單一。例如:AMD裏require分全局的和局部的。CMD裏面沒有全局的 require,提供 seajs.use()來實現模塊系統的加載啓動。CMD裏每個API都簡單純粹。
SeaJS 和 RequireJS的主要區別在此有解釋。
續:RequireJS及SeaJS與CommonJS的比較(嚴格意義上前兩者與後者不該放在一起比較,因爲前兩者是規範的具體實現而後者是一種規範)
RequireJS實現了AMD的API.
CommonJS是使用exports對象來定義模塊的一種方法,它定義了模塊的內容。簡單地實現一個CommonJS的定義就像下面這樣:
// someModule.js
exports.doSomething = function() { return "foo"; };
//otherModule.js
var someModule = require('someModule'); // in the vein of node
exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };
基本上CommonJS明確了你需要有一個require函數來獲取依賴,exports變量來輸出模塊的內容和一些用來獲取依賴的模塊標識符。CommonJS有多種實現,比如Node.js.
因爲CommonJS設計的時候沒有考慮瀏覽器,所以它不適合瀏覽器環境(我其實對這個不明確,但是這種說法到處都有,比如RequireJS官網)。所以我們得做一些工作來實現異步加載。
相反,RequireJS實現了AMD,它被設計用來適應瀏覽器環境。表面上看來,AMD開始是CommonJS輸出格式的副產品,而且最終進化出了自己的API。在AMD中出現的新東西是define函數,它允許模塊在加載依賴之前聲明它的依賴。例如定義可能就像下面這樣:
define('module/id/string', ['module', 'dependency', 'array'],
function(module, factory function) {
return ModuleContents;
});
因此CommonJS和AMD是Javascript模塊定義API的不同的實現,但是他們有相同的根源。AMD更適合瀏覽器,因爲它支持異步加載模塊依賴。RequireJS是AMD的一個實現,而且儘量保留了CommonJS的精神(主要是模塊標識符上)。更讓人混亂的是,RequireJS在實現AMD的同時,還提供了一個CommonJS包裹,這樣CommonJS模塊可以幾乎直接被RequireJS引入。
define(function(require, exports, module) {
var someModule = require('someModule'); // in the vein of node
exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };
});