js 模塊化CommonJS AMD UMD CMD ES6規(guī)范詳解
js 的演變
通過這篇文章,筆者將介紹幾種 js 模塊化的規(guī)范,以及它們各自的優(yōu)缺點和差異......
在 js 剛出現(xiàn)的時候,只是作為腳本語言,但隨著瀏覽器的不斷發(fā)展,js 越來越被重視起來,可以實現(xiàn)較為復雜的功能。這個時候開發(fā)者為了維護方便,會把不同功能的模塊抽離出來寫入單獨的 js 文件,但是當項目更為復雜的時候,html 中可能會引入很多個 js 文件,而這個時候就會出現(xiàn)命名沖突,污染作用域等一系列問題,這個時候 模塊化 的概念及實現(xiàn)方法應運而生。
模塊化
模塊化開發(fā)是一種管理方式,一種生產(chǎn)方式,也是一種解決問題的方案。一個模塊就是實現(xiàn)某個特定功能的文件,我們可以很方便的使用別人的代碼,想要什么模塊,就引入那個模塊。但是模塊開發(fā)要遵循一定的規(guī)范,后面就出現(xiàn)了我們所熟悉的一系列規(guī)范。
1. CommonJS 規(guī)范
CommonJS 主要用在 node 開發(fā)上,每個文件就是一個模塊,每個文件都有自己的一個作用域。通過module.exports 暴露 public 成員。
此外,CommonJS 通過 require 引入模塊依賴,require 函數(shù)可以引入 node 的內(nèi)置模塊、自定義模塊和 npm 等第三方模塊。
定義模塊:
// 定義模塊 math.js
var basicNum = 0;
function add(a, b) {
return a + b;
}
// 在這里寫上需要向外暴露的函數(shù)、變量
module.exports = {
add: add,
basicNum: basicNum
}
加載模塊:
// 引入 math.js 模塊
var math = require('./math');
math.add(2, 3); // 5
優(yōu)點:
- 簡單并且容易使用
- 服務器端模塊便于重用
缺點:
- 同步的模塊加載方式不適合在瀏覽器環(huán)境中
- 不能非阻塞的并行加載多個模塊
2. AMD 規(guī)范
AMD 是 (Asynchronous Module Definition) 的縮寫,意思就是"異步模塊定義"。它采用異步方式加載模塊,模塊的加載不影響它后面語句的運行。所有依賴這個模塊的語句,都定義在一個回調(diào)函數(shù)中,等到加載完成之后,這個回調(diào)函數(shù)才會運行。
在 AMD 規(guī)范中,我們使用 define 定義模塊,使用 require 加載模塊,但是不同于 CommonJS,它要求兩個參數(shù):
定義模塊:
define(id?, dependencies?, factory);
id是定義的模塊名,這個參數(shù)是 可選的,如果沒有定義該參數(shù),模塊名字應該默認為模塊加載器請求的指定腳本的名字,如果有該參數(shù),模塊名必須是頂級的絕對的。dependencies是定義的模塊中所依賴的 模塊數(shù)組,也是 可選的,依賴模塊優(yōu)先級執(zhí)行,并且執(zhí)行結果按照數(shù)組中的排序依次以參數(shù)的形式傳入factory。factory是模塊初始化要執(zhí)行的函數(shù)或?qū)ο?,?必需的。
加載模塊:
require([module], callback);
第一個參數(shù) module,是一個數(shù)組,里面的成員就是要加載的模塊;第二個參數(shù) callback,則是加載成功之后的回調(diào)函數(shù)。如果將前面的 CommonJS 改寫成 AMD 形式,就是下面這樣:
require(['./math'], function (math) {
math.add(2, 3);
});
優(yōu)點:
- 適合在瀏覽器環(huán)境中異步加載模塊
- 可以并行加載多個模塊
缺點:
- 提高了開發(fā)成本
- 不符合通用的模塊化思維方式
3. UMD 規(guī)范
UMD 是 (Universal Module Definition) 通用模塊定義 的縮寫。UMD 是 AMD 和 CommonJS 的一個糅合。AMD 是瀏覽器優(yōu)先,異步加載;CommonJS 是服務器優(yōu)先,同步加載。
既然要通用,怎么辦呢?那就先判斷是否支持 node 的模塊,支持就使用 node;再判斷是否支持 AMD,支持則使用 AMD 的方式加載。這就是所謂的 UMD。
示例:
(function (window, factory) {
if (typeof exports === "object") {
// CommonJS
module.exports = factory();
} else if (typeof define === "function" && define.amd) {
// AMD
define(factory);
} else {
// 瀏覽器全局定義
window.eventUtil = factory();
}
})(this, function () {
// do something
});
4. CMD 規(guī)范
CMD 是 (Common Module Definition) 公共模塊定義 的縮寫。CMD 可能是在 CommonJS 之后抽象出來的一套模塊化語法定義和使用的標準。
在 CMD 規(guī)范中,一個模塊就是一個文件。
定義模塊:
define(factory);
define 接收 factory 參數(shù),它可以是一個函數(shù),也可以是一個對象或一個字符串。
- 當
factory是一個對象或是一個字符串時,表示該模塊的接口就是這個對象或者字符串。 - 當
factory是一個函數(shù)時,表示是該模塊的構造方法。執(zhí)行該構造方法,可以得到模塊向外提供的接口。factory在執(zhí)行時,默認傳入三個參數(shù):require、exports、module。其中require用來加載其它模塊,exports用來向外提供模塊接口。module是一個對象,存儲著與當前模塊相關聯(lián)的一些屬性和方法。
加載模塊:
我們可以通過 SeaJs 的 use 方法加載模塊:
seajs.use([module], callback);
優(yōu)點:可以很容易在 node 中運行
缺點:依賴 SPM 打包,模塊的加載邏輯偏重
5. ES6 模塊化
ES6 模塊的設計思想是盡量的 靜態(tài)化,使得編譯時就能確定模塊的依賴關系,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運行時確定這些東西。
在 ES6 中,我們使用 export 關鍵字來導出模塊,使用 import 關鍵字來引入模塊。
引入模塊:
// ES6模塊
import { stat, exists, readFile } from 'fs';
上面代碼實質(zhì)是從 fs 模塊中加載 3 個方法,其他方法不加載。這種加載稱為 “編譯時加載” 或者 靜態(tài)加載,即 ES6 可以在編譯時就完成模塊加載,效率要比 CommonJS 模塊的加載方式高。當然,這也導致了沒法引用 ES6 模塊本身,因為它不是對象。
導出模塊:
let firstName = 'Zhou';
let lastName = 'ShuYi';
let year = 1994;
export { firstName, lastName, year };
上面代碼在 export 后面,使用大括號指定所要輸出的一組變量。export 除了輸出變量,還可以輸出函數(shù)或類。
優(yōu)點:容易進行靜態(tài)分析
缺點:原生瀏覽器端還沒有實現(xiàn)該標準
AMD 和 CMD 的區(qū)別
對于依賴的模塊,AMD 是 提前執(zhí)行,CMD 是 延遲執(zhí)行。
AMD 推崇 依賴前置,CMD 推崇 依賴就近。
AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區(qū)分,推崇職責單一。
ES6 模塊與 CommonJS 模塊的差異
CommonJS 模塊輸出的是一個 值的拷貝,ES6 模塊輸出的是 值的引用。
CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口。
CommonJS 模塊的 require() 是 同步加載 模塊,ES6 模塊的 import 命令是 異步加載,有一個獨立的模塊依賴的解析階段。
最后
以上就是筆者對于 js 模塊化的一些理解,更多關于js 模塊化規(guī)范的資料請關注腳本之家其它相關文章!
相關文章
javascript 在firebug調(diào)試時用console.log的方法
當你使用console.log()函數(shù)時,下面的firebug一定要打開,不然這函數(shù)在用firefox運行時無效且影響正常程序,如果用IE打開,將會出錯2012-05-05
JS 通過系統(tǒng)時間限定動態(tài)添加 select option的實例代碼
這篇文章主要介紹了JS 通過系統(tǒng)時間限定 動態(tài)添加 select option的實例代碼,非常不錯具有參考借鑒價值,需要的朋友可以參考下2016-06-06
編寫跨瀏覽器的javascript代碼必備[js多瀏覽器兼容寫法]
下面比較了幾種瀏覽器之間的差異,在寫javascript代碼時 要時刻注意這些差異2008-10-10

