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