模塊化發(fā)展歷程
js一開始并沒有模塊化的概念,直到ajax被提出,前端能夠像后端請求數(shù)據(jù),前端邏輯越來越復(fù)雜,就出現(xiàn)了許多問題:全局變量,函數(shù)名沖突,依賴關(guān)系不好處理。
當(dāng)時(shí)使用子執(zhí)行函數(shù)來解決這些問題,比如經(jīng)典的jquery就使用了匿名自執(zhí)行函數(shù)封裝代碼,將他們?nèi)紥燧d到全局變量jquery下邊。
CommonJs
CommonJs通過nodeJs發(fā)揚(yáng)光大,每個(gè)js文件就是一個(gè)模塊,每個(gè)模塊有單獨(dú)的作用域。模塊以module.exports為出口,輸出一個(gè)對象。使用require方法讀取文件,并返回其內(nèi)部的module.exports對象。
CommonJs的問題在于,他的加載是同步的,這在服務(wù)端很正常,但是在充滿了異步的瀏覽器里,就不適用了。為了適應(yīng)瀏覽器,社區(qū)內(nèi)部發(fā)生了分歧。
AMD
AMD 即Asynchronous Module Definition,中文名是異步模塊定義的意思。它是一個(gè)在瀏覽器端模塊化開發(fā)的規(guī)范,由于不是JavaScript原生支持,AMD的作者親自實(shí)現(xiàn)了符合AMD規(guī)范的RequireJS。
AMD規(guī)范規(guī)定用全局函數(shù)define來定義模塊,用法為define(id, dependencies, factory);其中,id為模塊標(biāo)識,dependencies是一個(gè)數(shù)組,數(shù)組里邊是該模塊依賴的其他模塊,factory則是一個(gè)匿名函數(shù),里邊是該模塊的邏輯。
目前公司使用的就是AMD規(guī)范。
例如:
//main.js
require(['a', 'b'], function(a, b){
console.log('main.js執(zhí)行');
a.hello();
$('#b').click(function(){
b.hello();
});
})
requireJs的問題在于,加在一個(gè)模塊時(shí),會(huì)預(yù)先加載該模塊的所有依賴模塊,但是這些依賴很可能一開始并不用到。同時(shí)依賴寫起來一長串,也很麻煩。比較好的是AMD保留了commonJs中的require、exprots、module3個(gè)功能,可以不把以來都寫在dependencies中,而是在需要時(shí)使用require引入。
CMD
既然requirejs有上述種種不甚優(yōu)雅的地方,所以必然會(huì)有新東西來完善它,這就是后起之秀seajs,seajs的作者是國內(nèi)大牛淘寶前端步道者玉伯。seajs全面擁抱Modules/Wrappings規(guī)范,不用requirejs那樣回調(diào)的方式來編寫模塊。而它也不是完全按照Modules/Wrappings規(guī)范,seajs并沒有使用declare來定義模塊,而是使用和requirejs一樣的define,或許作者本人更喜歡這個(gè)名字吧。(然而這或多或少又會(huì)給人們造成理解上的混淆),用seajs定義模塊的寫法如下:
//main.js
define(function(require, exports, module){
console.log('main.js執(zhí)行');
var a = require('a');
a.hello();
$('#b').click(function(){
var b = require('b');
b.hello();
});
});
定義模塊時(shí)無需羅列依賴數(shù)組,在factory函數(shù)中需傳入形參require,exports,module,然后它會(huì)調(diào)用factory函數(shù)的toString方法,對函數(shù)的內(nèi)容進(jìn)行正則匹配,通過匹配到的require語句來分析依賴,這樣就真正實(shí)現(xiàn)了commonjs風(fēng)格的代碼。
AMD與CMD的區(qū)別
AMD和CMD最明顯的區(qū)別就是在模塊定義時(shí)對依賴的處理不同
AMD推崇依賴前置,在定義模塊的時(shí)候就要聲明其依賴的模塊
CMD推崇就近依賴,只有在用到某個(gè)模塊的時(shí)候再去require
這種區(qū)別各有優(yōu)劣,只是語法上的差距,而且requireJS和SeaJS都支持對方的寫法
面向未來的ES6模塊標(biāo)準(zhǔn)
ES6考慮了模塊化,使用import和export,但是目前瀏覽器還不支持,這個(gè)標(biāo)準(zhǔn)也只是個(gè)雛形。
作者:
黑馬程序員前端與移動(dòng)開發(fā)培訓(xùn)學(xué)院首發(fā):
http://web.itheima.com/