模塊化規(guī)范:CommonJS,AMD,CMD,UMD,ES6 Module
CommonJS
CommonJS是服務(wù)器端模塊的規(guī)范,Node.js采用了這個(gè)規(guī)范。是一種同步的方式。
根據(jù)CommonJS規(guī)范,一個(gè)單獨(dú)的文件就是一個(gè)模塊,使用exports/require方法。
//導(dǎo)出 module.exports
module.exports = { age: 1, a: 'hello', foo:function(){} }
//nodeJS中同步加載
var math = require('math');
math.add(2,3);
服務(wù)器端的編程,需要加載的模塊文件一般都已經(jīng)存在本地硬盤(pán),加載起來(lái)比較快,所以CommonJS規(guī)范比較適用。但是在瀏覽器中如果用同步加載的方式會(huì)導(dǎo)致頁(yè)面卡頓,影響用戶(hù)體驗(yàn),所以就有了AMD。
AMD與RequireJS
AMD是"Asynchronous Module Definition"的縮寫(xiě),意思就是"異步模塊定義"。它采用異步方式加載模塊,模塊的加載不影響它后面語(yǔ)句的運(yùn)行。
所有依賴(lài)這個(gè)模塊的語(yǔ)句,都定義在一個(gè)回調(diào)函數(shù)中,等到加載完成之后,這個(gè)回調(diào)函數(shù)才會(huì)運(yùn)行
//模塊定義 define(id?, dependencies?, factory)
define("alpha", [ "require", "exports", "beta" ], function( require, exports, beta ){
exports.verb = function(){
return beta.verb();
}
});
//模塊加載 require([module], callback)
require(['math'], function(math) {
math.add(2, 3);
});
RequireJS
RequireJS 是一個(gè)前端的模塊化管理的工具庫(kù),遵循AMD規(guī)范。
RequireJS 的基本思想為:通過(guò)一個(gè)函數(shù)來(lái)將所有所需要的或者說(shuō)所依賴(lài)的模塊實(shí)現(xiàn)裝載進(jìn)來(lái),然后返回一個(gè)新的函數(shù)(模塊),我們所有的關(guān)于新模塊的業(yè)務(wù)代碼都在這個(gè)函數(shù)內(nèi)部操作,其內(nèi)部也可無(wú)限制的使用已經(jīng)加載進(jìn)來(lái)的以來(lái)的模塊。
define定義模塊
//獨(dú)立模塊,不依賴(lài)其他模塊
define(function() {
return {
method1: function(){},
method2: function(){}
}
});
//非獨(dú)立模塊 define([modules], callback);
define([ 'module1', 'module2' ], function(m1, m2) {
...
});
require方法調(diào)用模塊
//require([modules], callback);
require(['foo', 'bar'], function(foo, bar) {
foo.func();
bar.func();
} );
CMD和SeaJS
AMD是"Common Module Definition" ,AMD是依賴(lài)前置(預(yù)加載),而CMD是依賴(lài)就近,想什么時(shí)候 require就什么時(shí)候加載,實(shí)現(xiàn)了懶加載(延遲執(zhí)行 )
CMD沒(méi)有全局 require, 每個(gè)API都簡(jiǎn)單純粹。
// CMD
define(function(require, exports, module) {
var a = require('./a')
a.doSomething();
...
var b = require('./b') // 依賴(lài)可以就近書(shū)寫(xiě)
b.doSomething();
})
雖然RequireJS也支持SeaJS的寫(xiě)法,但是依賴(lài)的模塊任然是預(yù)先加載的
UMD
UMD(Universal Module Definition)是AMD+CommonJS+全局變量的結(jié)合
UMD先判斷是否支持Node.js的模塊(exports)是否存在,存在則使用Node.js模塊模式。
再判斷是否支持AMD(define是否存在),存在則使用AMD方式加載模塊。
(function (window, factory) {
if (typeof exports === 'object')
module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
define(factory);
} else {
window.eventUtil = factory();
}
})(this, function () {
//module ...
});
有了 UMD 后我們的代碼和同時(shí)運(yùn)行在 Node 和 瀏覽器上,所以現(xiàn)在前端大多數(shù)的庫(kù)最后打包都使用的是 UMD 規(guī)范
ES6 Module
ES6后直接使用export/import就可以進(jìn)行模塊管理,不再需要AMD, CommonJS
export * from 'module'; //重定向?qū)С?不包括 module內(nèi)的default
export { name1, name2, ..., nameN } from 'module'; // 重定向命名導(dǎo)出
export { import1 as name1, import2 as name2, ..., nameN } from 'module'; // 重定向重命名導(dǎo)出
export { name1, name2, …, nameN }; // 與之前聲明的變量名綁定 命名導(dǎo)出
export { variable1 as name1, variable2 as name2, …, nameN }; // 重命名導(dǎo)出
export let name1 = 'name1'; // 聲明命名導(dǎo)出 或者 var, const,function, function*, class
export default expression; // 默認(rèn)導(dǎo)出
export default function () { ... } // 或者 function*, class
export default function name1() { ... } // 或者 function*, class
import { a, b, c } from 'module'; //命名導(dǎo)出
import { a as newA, b, c as newC } from 'module';
import 'module'; // 副作用,只是運(yùn)行module,不為了導(dǎo)出內(nèi)容,多次調(diào)用次語(yǔ)句只能執(zhí)行一次
var promise = import('module'); //動(dòng)態(tài)導(dǎo)入(異步導(dǎo)入)
注意項(xiàng)
1.語(yǔ)法是靜態(tài)的,import 會(huì)自動(dòng)提升到代碼的頂層
2.使用 import 導(dǎo)入的變量是只讀的,無(wú)法被賦值,而且是引用傳遞
與CommonJs的區(qū)別
1.CommonJs導(dǎo)出的是變量的一份拷貝,ES6 Module導(dǎo)出的是變量的綁定(引用)
2.CommonJs是單個(gè)值導(dǎo)出,ES6 Module可以導(dǎo)出多個(gè)
3.CommonJs是動(dòng)態(tài)語(yǔ)法可以寫(xiě)在判斷里,ES6 Module靜態(tài)語(yǔ)法只能寫(xiě)在頂層
4.CommonJs的 this 是當(dāng)前模塊,ES6 Module的 this 是 undefined