CommonJs用在服務器端,AMD和CMD用在瀏覽器環境
AMD 是 RequireJS 在推廣過程中對模塊定義的規範化產出。提前執行(異步加載:依賴先執行)+延遲執行
CMD 是 SeaJS 在推廣過程中對模塊定義的規範化產出。延遲執行(運行到需加載,根據順序執行)
模塊
- 函數寫法
function f1(){
//...
}
function f2(){
//...
}
模塊就是實現特定功能的文件,把幾個函數放在一個文件裏就構成了一個模塊。需要的時候加載這個文件,調用其中的函數即可。但這樣做會污染全局變量,無法保證不與其他模塊發生變量名衝突,而且模塊成員之間沒什麼關係。
- 對象寫法
var module = {
star : 0,
f1 : function (){
//...
},
f2 : function (){
//...
}
};
module.f1();
module.star = 1;
模塊寫成一個對象,模塊成員都封裝在對象裏,通過調用對象屬性,訪問使用模塊成員。但同時也暴露了模塊成員,外部可以修改模塊內部狀態。
- 立即執行函數
var module = (function(){
var star = 0;
var f1 = function (){
console.log('ok');
};
var f2 = function (){
//...
};
return {
f1:f1,
f2:f2
};
})();
module.f1(); //ok
console.log(module.star) //undefined
外部無法訪問內部私有變量
CommonJs
CommonJS是服務器端模塊的規範,由Node推廣使用。由於服務端編程的複雜性,如果沒有模塊很難與操作系統及其他應用程序互動。require()用來引入外部模塊;exports對象用於導出當前模塊的方法或變量,唯一的導出口;module對象就代表模塊本身,使用方法如下:
math.js
exports.add = function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
increment.js
var add = require('math').add;
exports.increment = function(val) {
return add(val, 1);
};
index.js
var increment = require('increment').increment;
var a = increment(1); //2
根據CommonJS規範:
一個單獨的文件就是一個模塊。每一個模塊都是一個單獨的作用域,也就是說,在該模塊內部定義的變量,無法被其他模塊讀取,除非定義爲
global
對象的屬性。輸出模塊變量的最好方法是使用
module.exports
對象。加載模塊使用
require
方法,該方法讀取一個文件並執行,返回文件內部的module.exports
對象
仔細看上面的代碼,您會注意到 require
是同步的。模塊系統需要同步讀取模塊文件內容,並編譯執行以得到模塊接口。
然而, 這在瀏覽器端問題多多。
瀏覽器端,加載 JavaScript 最佳、最容易的方式是在 document
中插入<script>
標籤。但腳本標籤天生異步,傳統 CommonJS 模塊在瀏覽器環境中無法正常加載。
解決思路之一是,開發一個服務器端組件,對模塊代碼作靜態分析,將模塊與它的依賴列表一起返回給瀏覽器端。 這很好使,但需要服務器安裝額外的組件,並因此要調整一系列底層架構。
另一種解決思路是,用一套標準模板來封裝模塊定義:
define(function(require, exports, module) {
// The module code goes here
});
這套模板代碼爲模塊加載器提供了機會,使其能在模塊代碼執行之前,對模塊代碼進行靜態分析,並動態生成依賴列表。
math.js
define(function(require, exports, module) {
exports.add = function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
});
increment.js
define(function(require, exports, module) {
var add = require('math').add;
exports.increment = function(val) {
return add(val, 1);
};
});
index.js
define(function(require, exports, module) {
var inc = require('increment').increment;
inc(1); // 2
});
AMD
AMD是"Asynchronous Module Definition"
的縮寫,意思就是"異步模塊定義"。由於不是JavaScript原生支持,使用AMD規範進行頁面開發需要用到對應的庫函數,也就是大名鼎鼎RequireJS
,實際上AMD 是 RequireJS
在推廣過程中對模塊定義的規範化的產出。它採用異步方式加載模塊,模塊的加載不影響它後面語句的運行。所有依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成之後,這個回調函數纔會運行。
RequireJS
主要解決兩個問題
- 多個js文件可能有依賴關係,被依賴的文件需要早於依賴它的文件加載到瀏覽器
- js加載的時候瀏覽器會停止頁面渲染,加載文件越多,頁面失去響應時間越長
RequireJs也採用require()語句加載模塊,但是不同於CommonJS,它要求兩個參數:
第一個參數[module],是一個數組,裏面的成員就是要加載的模塊;第二個參數callback,則是加載成功之後的回調函數。math.add()與math模塊加載不是同步的,瀏覽器不會發生假死。
require([module], callback);
require([increment'], function (increment) {
increment.add(1);
});
define()函數
RequireJS
定義了一個函數 define
,它是全局變量,用來定義模塊:define(id?, dependencies?, factory);
參數說明:
id:指定義中模塊的名字,可選;如果沒有提供該參數,模塊的名字應該默認爲模塊加載器請求的指定腳本的名字。如果提供了該參數,模塊名必須是“頂級”的和絕對的(不允許相對名字)。
依賴dependencies:是一個當前模塊依賴的,已被模塊定義的模塊標識的數組字面量。
依賴參數是可選的,如果忽略此參數,它應該默認爲["require", "exports", "module"]。然而,如果工廠方法的長度屬性小於3,加載器會選擇以函數的長度屬性指定的參數個數調用工廠方法。工廠方法factory,模塊初始化要執行的函數或對象。如果爲函數,它應該只被執行一次。如果是對象,此對象應該爲模塊的輸出值。
來舉個