本文總結(jié)自網(wǎng)易云課堂-前端工程微專業(yè)課程
模塊組織(js腳本)
在構(gòu)件具有一定規(guī)模的項(xiàng)目時(shí)芬位,我們往往采用分割的形式,將一個(gè)項(xiàng)目中拆分成一個(gè)個(gè)的小模塊巩搏,這樣在開發(fā)和維護(hù)時(shí)册舞,會(huì)簡(jiǎn)單許多。而在不同的模塊中蹬挤,我們只需考慮模塊輸出的接口就可以了缚窿。但是在ES5及以下版本的規(guī)范中,模塊并沒(méi)有原生支持焰扳。那么如何編寫我們的代碼倦零,來(lái)巧妙的彌補(bǔ)這一缺陷呢?
模塊職責(zé):
封裝實(shí)現(xiàn)
暴露接口
聲明依賴(主要是模塊系統(tǒng)職責(zé))
1.反模塊
反模塊即不使用任何的模塊系統(tǒng)吨悍,所編寫的函數(shù)都散落在全局當(dāng)中扫茅,無(wú)封裝性,也沒(méi)有明顯的接口暴露育瓜,調(diào)用函數(shù)也沒(méi)有依賴聲明葫隙。這樣的做法是很危險(xiǎn)的,因?yàn)槟愕淖兞吭谌种絮锍穑蠹叶伎梢阅脕?lái)修改恋脚,特別是出現(xiàn)重名變量的時(shí)候,就會(huì)出現(xiàn)沖突焰手。
2.字面量
var math = {
add: function add(a, b){
return a+b;
},
sub: function sub(a, b){
return a-b;
}
}
//聲明一個(gè)math對(duì)象糟描,有兩個(gè)方法,我們很明顯的可以看出书妻,這個(gè)模塊輸出的方法很直觀船响。
var calculate = {
action: "add",
compute: function compute(a, b){
switch(this.action){
case "add": return math.add(a, b);
case "sub": return math.sub(a, b);//調(diào)用的時(shí)候也很簡(jiǎn)單。
}
}
}
由上可以看出,字面量清楚的描述了接口是什么见间,但是卻沒(méi)有訪問(wèn)限制聊闯,并且調(diào)用時(shí)也沒(méi)有依賴聲明。也就是說(shuō)缤剧,這個(gè)模塊沒(méi)有被封裝起來(lái)馅袁,我們可以在全局中任意的修改其中的所有屬性和方法。
3.IIFE(自執(zhí)行函數(shù)表達(dá)式)
var calculate = (function(){
var action = "add";
return{
compute: function compute(a, b){
switch(action){
case "add": return math.add(a, b);
case "sub": return math.sub(a, b);
}
}
}
} )();
//在js中荒辕,函數(shù)閉包能保存函數(shù)的上一級(jí)中變量的狀態(tài)汗销,所以這段代碼在執(zhí)行之后,action變量無(wú)法被改變抵窒,但卻可以被使用(僅在return出的函數(shù)中)弛针。
IIFE的方法實(shí)現(xiàn)了私有變量的訪問(wèn)控制,但依然沒(méi)有對(duì)應(yīng)的依賴聲明李皇,由此削茁,變出現(xiàn)了下面的這種形式:
var calculate = (function(m){//這里的m即傳入的math
var action = "add";
function compute(a, b){
switch(action){
case "add": return m.add(a, b);
case "sub": return m.sub(a, b);
}
}
return{
compute: compute//返回一個(gè)名叫compute的方法,這個(gè)方法是compute函數(shù)
}
})(math);//把math作為自執(zhí)行函數(shù)的參數(shù)傳入
這樣掉房,使用的也是IIFE方法茧跋,并且對(duì)于暴漏的接口也更方便去查找和更改。并且有了對(duì)依賴的聲明卓囚,只是我們需要手動(dòng)去管理依賴瘾杭,并且對(duì)于模塊的加載順序也有要求,被依賴的模塊必須首先被加載哪亿。并且會(huì)污染全局變量(var calculate有重名風(fēng)險(xiǎn))粥烁。
4.命名空間
為了避免IIFE污染全局變量的風(fēng)險(xiǎn),我們采用一種統(tǒng)一命名的方式蝇棉,來(lái)解決這個(gè)問(wèn)題讨阻。
var namespace = (function(){//namespace函數(shù)用來(lái)緩存所有的模塊,并且返回當(dāng)前組件篡殷。
var cache = {};//緩存所有模塊
function createModule(name, deps, definition){
console.log(arguments.length);
if(arguments.length == 1) return cache[name];
deps = deps.map(function(depName){
return cache[depName];//將依賴組件從cache中抽出
})
//程序的主體部分在此執(zhí)行钝吮,并且把返回的接口保存在cache中
cache[name] = definition.apply(null, deps)//將依賴組件當(dāng)成參數(shù)傳入調(diào)用函數(shù)中,這樣板辽,調(diào)用函數(shù)中便有了依賴組件奇瘦。
return cache[name];
}
return createModule;
})()
namespace("math", [], function(){//模塊聲明,依賴聲明戳气,以及模塊構(gòu)成
function add(a, b){return a+b}
function sub(a, b){return a-b}
return{//返回需要暴漏的接口
add: add,
sub: sub
}
});
namespace("calculate", ["math"], function(m){
var action = "add";
function compute(a, b){
return m[action](a, b);
}
return{
compute: compute
}
});
但是我們依然需要手動(dòng)的去管理依賴链患,那么巧鸭,使用什么辦法才能夠解決手動(dòng)依賴的弊端呢瓶您?這就需要使用民間的模塊系統(tǒng)來(lái)處理了。