一、CommonJS
CommonJS 原來叫 ServerJS,是以在浏覽器環境之外建構 JavaScript 生态系統為目标而産生的項目,比如在伺服器
和桌面環境中。
CommonJS 規範是為了解決 JavaScript 的作用域問題而定義的子產品形式,可以使每個子產品它自身的命名空間中執行。
該規範的主要内容是,子產品必須通過 module.exports 導出對外的變量或接口,通過 require() 來導入其他子產品的輸出到目前子產品作用域中。例子如下:
// moduleA.js
module.exports = function(x) {
return x * x;
};
// moduleB.js
const moduleA = require('./moduleA');
var result = moduleA();
CommonJS 是同步加載子產品。
NodeJs就是采用commonJs規範。
二、AMD
AMD(Asynchronous Module Definition)(異步子產品定義)是為浏覽器環境設計的,因為 CommonJS 子產品系統是同步加載的,目前浏覽器環境還沒有準備好同步加載子產品的條件。
AMD 定義了一套 JavaScript 子產品依賴異步加載标準,來解決同步加載的問題。
子產品通過 define 函數定義在閉包中,格式如下:
define(id?: String, dependencies?: String[], factory: Function|Object);
id 是子產品的名字,它是可選的參數。
dependencies 指定了所要依賴的子產品清單,它是一個數組,也是可選的參數,每個依賴的子產品的輸出将作為參數一次傳入 factory 中。如果沒有指定 dependencies,那麼它的預設值是 [“require”, “exports”, “module”]。
define(function(require, exports, module) {})
factory 是最後一個參數,它包裹了子產品的具體實作,它是一個函數或者對象。如果是函數,那麼它的傳回值就是子產品的輸出接口或值。
定義一個名為 moduleA 的子產品,它依賴 jQuery 子產品:
define('moduleA', ['jquery'], function($) {
// $ 是 jquery 子產品的輸出
$('body').text('hello world');
});
// 使用
define(['moduleA'], function(moduleA) {});
RequireJS就是采用AMD規範。
三、CMD
CMD(Common Module Definition),在 CMD 規範中,一個子產品就是一個檔案。
代碼的書寫格式如下:
define(factory);
define是全局函數,用來定義子產品。define接收factory參數,factory可以是函數,對象或字元串。
factory為對象或字元串時,表示該子產品的接口就是該對象或字元串,比如要定義一個json資料子產品:
define({"key" : "val"});
也可以通過字元串定義模闆子產品:
define("Hello {{name}}!")
factory是函數時,表示是子產品的構造方法。執行該構造方法,可以得到子產品對外提供的接口,factory方法在執行時,預設會傳入三個參數,require,exports,module。
define(function(require, exports, module) {
// 需要導出的子產品
});
require是方法,接收模闆辨別作為唯一參數,用來擷取其他子產品提供的接口:
define(function(require, exports) {
const a = require('./a');
a.doSomething();
});
require是同步往下執行的,require.async(id, callback?)用來在子產品内部異步加載子產品,并在加載完後執行回調函數:
define(function(require, exports) {
require.async(['./a', './b'], function(c, d) {
c.doSomething();
d.doSomething();
});
});
factory是函數時的第二個參數exports,exports是一個對象,用來對外提供子產品接口。
define(function(require, exports) {
exports.str = 'xxxxx'; // 對外提供str屬性
exports.doSomething = function() { // 對外提供 doSomething() 方法
// TODO
};
});
除了exports外,還可以用return直接對外提供對象接口
define(function(require, exports) {
return {
str : 'xxxxx' ,
doSomething : function() {}
};
});
exports是module.exports對象的一個引用,很多時候exports都無法滿足要求,例如對外提供一個執行個體對象:
define(function(require, exports, module) {
function Person(name, age) {
this.name = name;
this.age = age;
}
module.exports = new Person('lily', ); // 對外提供執行個體化後的Person對象。
});
module.exports還可以對外提供一個函數(exports不可以):
define(function(require, exports, module) {
var Person = function(name, age) {
this.name = name;
this.age = age;
}
module.exports = Person; // 對外提供Person函數。
});
sea.js就是采用CMD規範。
四、AMD+CMD比較
AMD預設是依賴前置,在一開始就将需要依賴的檔案配置并加載好:
define('moduleA', ['jquery'], function($) {
// 依賴的配置檔案已經配置并加載好了。
$('body').text('hello world');
});
CMD是依賴就近,需要使用的時候才會去配置加載:
define(function(require, exports) {
var a = require('./a.js'); // 配置并加載,同步
if(false) {
var b = require('./b.js'); // 該配置的檔案永遠不會去加載,
}
});