為什么要使用模塊化?
隨著互聯(lián)網(wǎng)技術(shù)的發(fā)展,網(wǎng)頁的JavaScript代碼越來越龐大,越來越復(fù)雜,復(fù)雜的網(wǎng)頁通常需要團隊分工合作、進度管理等,開發(fā)者迫切需要能隔離、組織龐大的JavaScript代碼的功能,也就是這里所說的模塊化。
一個模塊就是一個實現(xiàn)特定功能的文件,有了模塊,我們就可以更方便地使用別人的代碼,想要什么功能,就加載什么模塊。同時還解決了命名沖突,變量污染等問題。
模塊化開發(fā)規(guī)范在前端先驅(qū)們的探索中一步步形成。從最開始的函數(shù)封裝 --->對象-->立即執(zhí)行函數(shù),到后來的CommonJS、AMD、CMD。
CommonJS、AMD、CMD
- CommonJS規(guī)范
CommonJS是服務(wù)器端模塊的規(guī)范,Node.js采用了這個規(guī)范。Node.JS首先采用了js模塊化的概念。它的主要內(nèi)容:
定義模塊 根據(jù)CommonJS規(guī)范,一個單獨的文件就是一個模塊。每一個模塊都是一個單獨的作用域,也就是說,在該模塊內(nèi)部定義的變量,無法被其他模塊讀取,除非定義為global對象的屬性
模塊輸出: 模塊只有一個出口,module.exports對象,我們需要把模塊希望輸出的內(nèi)容放入該對象
加載模塊: 加載模塊使用require方法,該方法讀取一個文件并執(zhí)行,返回文件內(nèi)部的module.exports對象。
//模塊定義 myModel.js
var name = 'Byron';
function printName(){
console.log(name);
}
module.exports = {
printName: printName,
}
//加載模塊
var nameModule = require('./myModel.js');
nameModule.printName();
CommonJS的局限:由于require是同步的,模塊系統(tǒng)需要同步讀取模塊文件內(nèi)容,并編譯執(zhí)行以得到模塊接口。這在服務(wù)器端可以很好的執(zhí)行,因為模塊都放在本地硬盤,直接讀取就行了。但CommonJS卻不適合瀏覽器環(huán)境,比如:
var math = require('math');
math.add(2, 3);
后面的代碼執(zhí)行依賴于前面加載的模塊math,瀏覽器加載是異步的,如果加載時間很長,后面的代碼也無法執(zhí)行,會一直卡在那里。為了解決這個問題,誕生了AMD和CMD規(guī)范。
- AMD
AMD 即Asynchronous Module Definition,中文名是異步模塊定義的意思。語法:
1.用define來定義模塊。
define(id?, dependencies?, factory);
id:可選參數(shù),用來定義模塊的標識,如果沒有提供該參數(shù),腳本文件名(去掉拓展名)
dependencies:是一個當前模塊依賴的模塊名稱數(shù)組
factory:工廠方法,模塊初始化要執(zhí)行的函數(shù)或?qū)ο蟆H绻麨楹瘮?shù),它應(yīng)該只被執(zhí)行一次。如果是對象,此對象應(yīng)該為模塊的輸出值
2.用require來加載模塊。
require([dependencies], function(){});
require()函數(shù)接受兩個參數(shù):
第一個參數(shù)是一個數(shù)組,表示所依賴的模塊
第二個參數(shù)是一個回調(diào)函數(shù),當前面指定的模塊都加載成功后,它將被調(diào)用。加載的模塊會以參數(shù)形式傳入該函數(shù),從而在回調(diào)函數(shù)內(nèi)部就可以使用這些模塊
require()函數(shù)在加載依賴的函數(shù)的時候是異步加載的,這樣瀏覽器不會失去響應(yīng),它指定的回調(diào)函數(shù),只有前面的模塊都加載成功后,才會運行,解決了依賴性的問題。
- CMD
CMD([Common Module Definition] 模塊定義規(guī)范。在 CMD 規(guī)范中,一個模塊就是一個文件。代碼的書寫格式如下:
define(function(require, exports, module) {
// 模塊代碼
});
require 是一個方法,接受 模塊標識 作為唯一參數(shù),用來獲取其他模塊提供的接口;exports 是一個對象,用來向外提供模塊接口;module 是一個對象,上面存儲了與當前模塊相關(guān)聯(lián)的一些屬性和方法。
- AMD和CMD的區(qū)別:
AMD 是 RequireJS 在推廣過程中對模塊定義的規(guī)范化產(chǎn)出。
CMD 是 SeaJS 在推廣過程中對模塊定義的規(guī)范化產(chǎn)出。
AMD:提前執(zhí)行(異步加載:依賴先執(zhí)行)+延遲執(zhí)行。
CMD:延遲執(zhí)行(運行到需加載,根據(jù)順序執(zhí)行)。
CMD 推崇依賴就近,AMD 推崇依賴前置。
// CMD
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// 此處略去 100 行
var b = require('./b') // 依賴可以就近書寫
b.doSomething()
// ...
})
// AMD 默認推薦的是
define(['./a', './b'], function(a, b) { // 依賴必須一開始就寫好
a.doSomething()
// 此處略去 100 行
b.doSomething()
...
})