開發的時候,我們經常會把某些功能封裝成可複用的模塊。模塊封裝了功能,並且對外暴露一個API。隨着Node.js的誕生和發展,JavaScript可以在服務端運行,同時客戶端應用也越來越流行,JavaScript界產生了對優秀和健壯模塊系統的需求。在JavaScript中定義模塊的規範也隨之產生。
這裏,將詳細介紹最常見的兩個定義模塊的方法AMD和CommonJS,以及它們的結合UMD.
一、CommonJS
CommonJS模塊可以說是當前最流行的模塊定義規範。相比於AMD,它的工作效率更高、語法更簡單。一開始,CommonJS模塊是JavaScript服務器模塊的規範。
基本原理
實現編譯代碼,創建一個比原先更大的代碼包,其中包含了所有應用運行所需的代碼。
語法
const $ = require('jquery'); //將依賴加載到當前文件
exports.init = function(){
...
};
特點
- 沒有回調函數
- 同步加載,每個require語句會短暫阻塞代碼的運行,知道模塊加載完畢。不過這個加載不是通過網絡加載,而是從內存或者文件系統中加載,所以這個過程很快。
- 代碼簡單易懂
- CommonJS模塊不適合瀏覽器,因爲瀏覽器的加載機制不支持同步。需要用打包工具把所有CommonJS模塊打包成一個js文件。
二、AMD——爲瀏覽器設計的模塊定義規範
AMD:Asynchronous Module Definition(異步模塊規範),最老的方式之一,專爲瀏覽器而設計。
基本原理
用異步加載技術來定義模塊和依賴。提供define方法和require方法來定義和加載模塊。
語法
define方法:
define(
'模塊id',
['依賴數組'],
function([依賴數組]){ //工廠函數
...
}
);
工廠函數內部包含了模塊代碼,工廠函數最後返回的結果,就是要暴露給其他模塊的功能。
特點
- 用AMD定義的模塊至少需要一個工廠函數來暴露API給其他模塊使用。
- 依賴數組中的依賴會被異步加載。
- 模塊的加載通過客戶端(瀏覽器)向服務器發送HTTP請求來完成的,這個傳輸過程需要大量時間。
- 可以定義具名模塊,也可以定義匿名模塊。具名模塊通過開發者定義的名字加載,匿名模塊隱式的以文件名加載。
require方法:
require(['jquery'],
function($){ //回調函數
...
}
);
require方法與define方法相對應,用來顯示的加載模塊。
特點
- 可以在代碼的任何地方使用require加載另一個模塊。
- require調用會發送一個請求來下載模塊。
- 異步加載,只有在回調函數裏才能獲取新拿到的API。
AMD模塊加載流程示意圖
UMD——通用模塊規範
UMD:Universal Module Definition(通用模塊規範)是由社區想出來的一種整合了CommonJS和AMD兩個模塊定義規範的方法。
基本原理
用一個工廠函數來統一不同的模塊定義規範。
原則
- 所有定義模塊的方法需要單獨傳入依賴
- 所有定義模塊的方法都需要返回一個對象,供其他模塊使用
例如,利用UMD定義一個toggler模塊:
(function (global, factory) {
if (typeof exports === 'object' && typeof module !== undefined) { //檢查CommonJS是否可用
module.exports = factory(require('jquery'));
} else if (typeof define === 'function' && define.amd) { //檢查AMD是否可用
define('toggler', ['jquery', factory])
} else { //兩種都不能用,把模塊添加到JavaScript的全局命名空間中。
global.toggler = factory(global, factory);
}
})(this, function ($) {
function init() {
}
return {
init: init
}
});