這篇文章主要介紹了了解Javascript的模塊化開發(fā),本文講解了為什么需要模塊化開發(fā),模塊化開發(fā)的形成原因等內(nèi)容,需要的朋友可以參考下
小A是某個(gè)創(chuàng)業(yè)團(tuán)隊(duì)的前端工程師,負(fù)責(zé)編寫項(xiàng)目的Javascript程序。
全局變量沖突
根據(jù)自己的經(jīng)驗(yàn),小A先把一些常用的功能抽出來,寫成函數(shù)放到一個(gè)公用文件base.js中:
代碼如下:
var _ = {
$: function(id) { return document.getElementById(id); },
getCookie: function(key) { ... },
setCookie: function(key, value) { ... }
};
小A把這些函數(shù)都放在_對(duì)象內(nèi),以防過多的全局變量造成沖突。他告訴團(tuán)隊(duì)的其他成員,如果誰想使用這些函數(shù),只要引入base.js就可以了。
小C是小A的同事,他向小A反映:自己的頁面引入了一個(gè)叫做underscore.js的類庫,而且,這個(gè)類庫也會(huì)占用_這個(gè)全局變量,這樣一來就會(huì)跟base.js中的_沖突了。小A心想,underscore.js是第三方類庫,估計(jì)不好改,但是base.js已經(jīng)在很多頁面鋪開,不可能改。最后小A只好無奈地把underscore.js占用的全局變量改了。
此時(shí),小A發(fā)現(xiàn),把函數(shù)都放在一個(gè)名字空間內(nèi),可以減少全局變量沖突的概率,卻沒有解決全局變量沖突這個(gè)問題。
依賴
隨著業(yè)務(wù)的發(fā)展,小A又編寫了一系列的函數(shù)庫和UI組件,比方說標(biāo)簽切換組件tabs.js,此組件需調(diào)用base.js以及util.js中的函數(shù)。
有一天,新同事小D跟小A反映,自己已經(jīng)在頁面中引用了tabs.js,功能卻不正常。小A一看就發(fā)現(xiàn)問題了,原來小D不知道tabs.js依賴于base.js以及util.js,他并沒有添加這兩個(gè)文件的引用。于是,他馬上進(jìn)行修改:
代碼如下:
<script src="tabs.js"></script>
<script src="base.js"></script>
<script src="util.js"></script>
然而,功能還是不正常,此時(shí)小A教訓(xùn)小D說:“都說是依賴,那被依賴方肯定要放在依賴方之前啊”。原來小D把base.js和util.js放到tabs.js之后了。
小A心想,他是作者,自然知道組件的依賴情況,但是別人就難說了,特別是新人。
過了一段時(shí)間,小A給標(biāo)簽切換組件增加了功能,為了實(shí)現(xiàn)這個(gè)功能,tabs.js還需要調(diào)用ui.js中的函數(shù)。這時(shí),小A發(fā)現(xiàn)了一個(gè)嚴(yán)重的問題,他需要在所有調(diào)用了tabs.js的頁面上增加ui.js的引用?。?!
又過了一段時(shí)間,小A優(yōu)化了tabs.js,這個(gè)組件已經(jīng)不再依賴于util.js,所以他在所有用到tabs.js的頁面中移除了util.js的引用,以提高性能。他這一修改,出大事了,測試組MM告訴他,有些頁面不正常了。小A一看,恍然大悟,原來某些頁面的其他功能用到了util.js中的函數(shù),他把這個(gè)文件的引用去掉導(dǎo)致出錯(cuò)了。為了保證功能正常,他又把代碼恢復(fù)了。
小A又想,有沒有辦法在修改依賴的同時(shí)不用逐一修改頁面,也不影響其他功能呢?
模塊化
小A逛互聯(lián)網(wǎng)的時(shí)候,無意中發(fā)現(xiàn)了一種新奇的模塊化編碼方式,可以把它之前遇到的問題全部解決。
在模塊化編程方式下,每個(gè)文件都是一個(gè)模塊。每個(gè)模塊都由一個(gè)名為define的函數(shù)創(chuàng)建。例如,把base.js改造成一個(gè)模塊后,代碼會(huì)變成這樣:
代碼如下:
define(function(require, exports, module) {
exports.$ = function(id) { return document.getElementById(id); };
exports.getCookie = function(key) { ... };
exports.setCookie = function(key, value) { ... };
});
base.js向外提供的接口都被添加到exports這個(gè)對(duì)象。而exports是一個(gè)局部變量,整個(gè)模塊的代碼都沒有占用半個(gè)全局變量。
那如何調(diào)用某個(gè)模塊提供的接口呢?以tabs.js為例,它要依賴于base.js和util.js:
代碼如下:
define(function(require, exports, module) {
var _ = require('base.js'), util = require('util.js');
var div_tabs = _.$('tabs');
// .... 其他代碼
});
一個(gè)模塊可以通過局部函數(shù)require獲取其他模塊的接口。此時(shí),變量_和util都是局部變量,并且,變量名完全是受開發(fā)者控制的,如果你不喜歡_,那也可以用base:
代碼如下:
define(function(require, exports, module) {
var base = require('base.js'), util = require('util.js');
var div_tabs = base.$('tabs');
// .... 其他代碼
});
一旦要移除util.js、添加ui.js,那只要修改tabs.js就可以了:
代碼如下:
define(function(require, exports, module) {
var base = require('base.js'), ui = require('ui.js');
var div_tabs = base.$('tabs');
// .... 其他代碼
});
加載器
由于缺乏瀏覽器的原生支持,如果我們要用模塊化的方式編碼,就必須借助于一個(gè)叫做加載器(loader)的東西。
目前加載器的實(shí)現(xiàn)有很多,比如require.js、seajs。而JRaiser類庫也有自己的加載器。
更多信息請(qǐng)查看IT技術(shù)專欄