CommonJS是一個更偏向於服務器端的規範。NodeJS採用了這個規範。CommonJS的一個模塊就是一個腳本文件。require命令第一次加載該腳本時就會執行整個腳本,而後在內存中生成一個對象。它有四個重要的環境變量爲模塊化的實現提供支持:module、exports、require、global。實際使用時,用module.exports定義當前模塊對外輸出的接口(不推薦直接用exports),用require加載模塊。
javascript
CommonJS模塊規範主要分爲三部分:模塊引用(require)、模塊定義(export)、模塊標識(module)。
前端
/*這是a.js*/
function sum(a,b) {
return a + b
}
module.exports = {
sum: sum
}複製代碼
調用:java
var math = require('./assets/js/a')
console.log(math)
console.log(math.sum(4,6))複製代碼
好處:node
CommonJS模塊規範很好地解決變量污染問題,每一個模塊具備獨立空間,互不干擾。後端
module exports require global,前端瀏覽器不支持,Nodejs中使用的是這個規範數組
故事:基於commonJS規範的nodeJS出來之後,服務端的模塊概念已經造成,很天然地,你們就想要客戶端模塊。並且最好二者可以兼容,在服務器和瀏覽器均可以運行。可是,因爲一個重大的侷限,使得CommonJS規範不適用於瀏覽器環境!瀏覽器
var math = require('./assets/js/a')緩存
math.sum(4,6)bash
第二行math.sum(4,6),在第一行require('./assets/js/a')以後運行,所以必須等a.js加載完成。也就是說,若是加載時間很長,整個應用就會停在那裏等。(說明require 是同步的。)這對服務器端不是一個問題,由於全部的模塊都存放在本地硬盤,能夠同步加載完成,等待時間就是硬盤的讀取時間。可是,對於瀏覽器,這倒是一個大問題,由於模塊都放在服務器端,等待時間取決於網速的快慢,可能要等很長時間,瀏覽器處於"假死"狀態。 所以,瀏覽器端的模塊,不能採用"同步加載"(synchronous),只能採用"異步加載"(asynchronous)。這就是AMD規範誕生的背景。服務器
CommonJS是主要爲了JS在後端的表現制定的,他是不適合前端的,AMD(異步模塊定義)出現了,它就主要爲前端JS的表現制定規範。
AMD是"Asynchronous Module Definition"的縮寫,意思就是"異步模塊定義"。它採用異步方式加載模塊,模塊的加載不影響它後面語句的運行。全部依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成以後,這個回調函數纔會運行。 AMD也採用require()語句加載模塊,可是不一樣於CommonJS,它要求兩個參數:
require([module], callback); 複製代碼
第一個參數[module],是一個數組,裏面的成員就是要加載的模塊;
第二個參數callback,則是加載成功以後的回調函數。
若是將前面的代碼改寫成AMD形式,就是下面這樣:
定義模塊 a.js
/*這是a.js*/
define(function(){
function sum(a,b){
return a + b
}
return {
sum: sum
}
})複製代碼
調用模塊
<script type="text/javascript" src="https://static1.niwodai.com/Public/Static/nwd/active/libjs/require.js"></script>
<script type="text/javascript">
require(['assets/js/a'],function(math) {
console.log(math)
console.log(math.sum(4,6))
})
</script>複製代碼
math.sum(4,6)與a.js模塊加載不是同步的,瀏覽器不會發生假死。因此很顯然,AMD比較適合瀏覽器環境。目前RequireJS就是實現了AMD規範。
總結:AMD規範則是非同步加載模塊,容許指定回調函數。
CMD推崇依賴就近,延遲執行。能夠把你的依賴寫進代碼的任意一行,CMD是SeaJS在推廣過程當中對模塊定義的規範化產出。一個模塊就是一個文件。代碼的書寫格式以下:
define(function(require, exports, module) {
// 模塊代碼
});複製代碼
require
是能夠把其餘模塊導入進來的一個參數;而exports
是能夠把模塊內的一些屬性和方法導出的;module
是一個對象,上面存儲了與當前模塊相關聯的一些屬性和方法。
AMD是依賴關係前置,在定義模塊的時候就要聲明其依賴的模塊;
CMD是按需加載依賴就近,只有在用到某個模塊的時候再去require:
定義模塊 c.js
/*這是c.js*/
define(function(require, exports, module) {
return result = "20"
})複製代碼
定義模塊b.js
define(function(require, exports, module) {
// 依賴能夠就近書寫
var $result = require('./c');
console.log($result)
function sum(a,b){
return a + b
}
return {
sum: sum
}
})複製代碼
加載模塊或調用模塊
<script type="text/javascript" src="https://static1.niwodai.com/Public/Static/nwd/active/libjs/sea.js"></script>
<script type="text/javascript">
seajs.use(['./assets/js/b.js'], function(math){
console.log(math);
console.log(math.sum(4,6))
});
</script>複製代碼
ES6 在語言標準的層面上,實現了模塊功能,並且實現得至關簡單,旨在成爲瀏覽器和服務器通用的模塊解決方案。其模塊功能主要由兩個命令構成:export
和import
。export
命令用於規定模塊的對外接口,import
命令用於輸入其餘模塊提供的功能。
定義模塊:
/*這是a.js*/
const result = "20"
let sum = function(a,b) {
return a + b
}
export {sum,result};複製代碼
調用模塊
import {sum,result} from './assets/js/a';
console.log(result)
console.log(sum)
console.log(sum(4,6))
複製代碼
注意:在ES6中,咱們可使用 import 關鍵字引入模塊,經過 exprot 關鍵字導出模塊,功能較之於前幾個方案更爲強大,也是咱們所推崇的,可是因爲ES6目前沒法在瀏覽器中執行,因此,咱們只能經過babel將不被支持的import編譯爲當前受到普遍支持的 require。ES6的模塊不是對象,import
命令會被 JavaScript 引擎靜態分析,在編譯時就引入模塊代碼,而不是在代碼運行時加載,因此沒法實現條件加載。也正由於這個,使得靜態分析成爲可能。
1. CommonJS 模塊輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用。 CommonJS 模塊輸出的是值的拷貝,也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。 ES6 模塊的運行機制與 CommonJS 不同。JS 引擎對腳本靜態分析的時候,遇到模塊加載命令import,就會生成一個只讀引用。等到腳本真正執行時,再根據這個只讀引用,到被加載的那個模塊裏面去取值。換句話說,ES6 的import有點像 Unix 系統的「符號鏈接」,原始值變了,import加載的值也會跟着變。所以,ES6 模塊是動態引用,而且不會緩存值,模塊裏面的變量綁定其所在的模塊。
2. CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口。 運行時加載: CommonJS 模塊就是對象;即在輸入時是先加載整個模塊,生成一個對象,而後再從這個對象上面讀取方法,這種加載稱爲「運行時加載」。 編譯時加載: ES6 模塊不是對象,而是經過 export 命令顯式指定輸出的代碼,import時採用靜態命令的形式。即在import時能夠指定加載某個輸出值,而不是加載整個模塊,這種加載稱爲「編譯時加載」。 CommonJS 加載的是一個對象(即module.exports屬性),該對象只有在腳本運行完纔會生成。而 ES6 模塊不是對象,它的對外接口只是一種靜態定義,在代碼靜態解析階段就會生成