JavaScript模塊化 --- Commonjs、AMD、CMD、ES6 modules

Commonjs規範

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模塊規範很好地解決變量污染問題,每一個模塊具備獨立空間,互不干擾。後端

CommonJS規範定義模塊十分簡單,接口十分簡潔。
CommonJS模塊規範支持引入和導出功能,能夠順暢鏈接各個模塊,實現彼此依賴關係。

總結:瀏覽器不兼容CommonJS的根本緣由,在於缺乏四個Node.js環境的變量。 

module exports  require global,前端瀏覽器不支持,Nodejs中使用的是這個規範數組

AMD規範

故事:基於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規範誕生的背景。服務器

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推崇依賴就近,延遲執行。能夠把你的依賴寫進代碼的任意一行,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 Module

ES6 在語言標準的層面上,實現了模塊功能,並且實現得至關簡單,旨在成爲瀏覽器和服務器通用的模塊解決方案。其模塊功能主要由兩個命令構成:exportimportexport命令用於規定模塊的對外接口,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 引擎靜態分析,在編譯時就引入模塊代碼,而不是在代碼運行時加載,因此沒法實現條件加載。也正由於這個,使得靜態分析成爲可能。


ES6 模塊與 CommonJS 模塊的差別

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 模塊不是對象,它的對外接口只是一種靜態定義,在代碼靜態解析階段就會生成

相關文章
相關標籤/搜索