AMD 是 RequireJS 在推廣過程中對模塊定義的規范化產出。
CMD 是 SeaJS 在推廣過程中對模塊定義的規范化產出。
CommonJS 是 服務器端模塊的規范,Node.js采用了這個規范
區別:
- 對于依賴的模塊,AMD 是提前執行,CMD 是延遲執行。
AMD:提前執行(異步加載:依賴先執行)+延遲執行
CMD:延遲執行(運行到需加載,根據順序執行)
- CMD 推崇依賴就近,AMD 推崇依賴前置。看代碼
// CMD
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// 此處略去 100 行
var b = require('./b') // 依賴可以就近書寫
b.doSomething()
// ...
})
// AMD 默認推薦的是
define(['./a', './b'], function(a, b) { // 依賴必須一開始就寫好
a.doSomething()
// 此處略去 100 行
b.doSomething()
...
})
雖然 AMD 也支持 CMD 的寫法,同時還支持將 require 作為依
賴項傳遞,但 RequireJS 的作者默認是最喜歡上面的寫法,也
是官方文檔里默認的模塊定義寫法。
3.AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啟動。CMD 里,每個 API 都簡單純粹。
Commonjs
var i = 1;
var max = 30;
module.exports = function () {
for (i -= 1; i++ < max; ) {
console.log(i);
}
max *= 1.1;
};
module.exports對象,定義了一個函數,該函數就是模塊外部與內部通信的橋梁。
加載模塊使用require方法,該方法讀取一個文件并執行,最后返回文件內部的module.exports對象。
兼容三者的方案
有人試圖實現兼容。也就是自己的代碼既能在node上運行,也能在符合amd規范的代碼環境中運行。于是產生了umd,其實umd并不算規范,而只能算一種兼容方案,它可以兼容CommonJS和AMD。
兼容amd和cmd
if(typeof define == 'function' && (define.amd != undefined || define.cmd != undefined) {
define(function() {
return fun();
});
}
在requirejs中,一個模塊可以如此去定義:
define({});
define(factory);
define(id,dependencies,factor);
define(dependencies,factor)
在seajs中也差不多,但是也有不同之處:
define({});
define(factory);
define(id,dependencies,factory);
define(id,factory);
前面三種都是一樣的,但是細節上也有所不同,第一種以對象的方式定義并不能解決我們插件中接口傳遞的目的,因此不考慮。剩下的就只有兩種相同的形式,但是就像前文說到的一樣,OMD是為了實現兼容,也就是說它必須作為框架被應用,框架的基礎代碼具有穩定性,不能讓用戶改來改去,否則也就失去了規范的意義。而在剩下的兩種中,define(id,dependencies,factory)的前兩個變量,都需要自己去定義,因此,也被排除。最終也就只有define(factory)這種形式被我們采用。
define(function(){
return {
fun1 : function(a,b) {},
fun2 : function(c,d) {}
}; // return的結果為一個對象
});
兼容comomjs
當define沒有被定義的時候,說明跟sea.js和require.js沒有任何關系了,這個時候,我們要檢查是否支持node.js。
如果是在node.js環境下運行,那么module和exports是一個由核心庫提供的全局變量。因此,只需要將插件提供的接口賦值給module.exports,就完成了當前文件(模塊)所提供的接口了。
兼容原生的javascript
當以上情況都不滿足的情況下,實際上,你所提供的接口,就是一個函數。你提供了一個fun1的接口,你就可以在其他javascript代碼中執行fun1()函數。
!!nodejs深入淺出代碼
;(function (name, definition) {
// 檢測上下文環境是否為AMD或CMD
var hasDefine = typeof define === 'function',
// 檢查上下文環境是否為Node
hasExports = typeof module !== 'undefined' && module.exports;
if (hasDefine) {
// AMD環境或CMD環境
define(definition);
} else if (hasExports) {
// 定義為普通Node模塊
module.exports = definition();
} else {
// 將模塊的執行結果掛在window變量中,在瀏覽器中this指向window對象
this[name] = definition();
}
})('hello', function () {
var hello = function () {};
return hello;
});