在談閉包之間,我們先看一下javascript的作用域,我們以函數(shù)舉例。
對(duì)一個(gè)函數(shù)來(lái)說(shuō)它的作用域分為三種:
函數(shù)定義作用域
函數(shù)調(diào)用作用域、
函數(shù)內(nèi)部作用域
以下是一段代碼:
var x="how are you";
var a=0;
function ab(){
? ? ? ?console.log('a=',a);
? ? ? ? console.log('x=',this.x);
}
function ac(){
? ? ? var a=100;
? ? ? var x="I'm fine";
? ? ? ab();
}
ac();
ab();
以下為輸出:

函數(shù)ac的輸出與函數(shù)ab的輸出一致,這是不是很奇怪?函數(shù)ac中定義了同名變量a=100,x="I'm fine",ac中調(diào)用了函數(shù)ab,但函數(shù)ab的輸出并沒(méi)有受到影響。
我們來(lái)看看《javascript權(quán)威指南》中對(duì)閉包的解釋,閉包就是調(diào)用一個(gè)函數(shù)時(shí),如果該函數(shù)內(nèi)函數(shù)體有對(duì)函數(shù)外變量的引用,函數(shù)被調(diào)用時(shí),就是會(huì)將函數(shù)以及函數(shù)引用的變量包裹起來(lái),這就形成了閉包。
我們?cè)賮?lái)看上面的例子,這是js閉包的經(jīng)典示例,我們不難發(fā)現(xiàn),js中對(duì)于函數(shù)的調(diào)用會(huì)回溯到函數(shù)定義時(shí)的作用域,函數(shù)的作用域就是函數(shù)定義的作用域,它和函數(shù)調(diào)用的作用域無(wú)關(guān)。所以無(wú)論函數(shù)ac內(nèi)變量怎么變換,都不會(huì)影響ac內(nèi)函數(shù)ab的輸出。
那么,在函數(shù)調(diào)用作用域與定義作用域不同的情況下,如果我們想讓函數(shù)的掉哦用作用域可以影響函數(shù)的輸出有什么辦法嗎?
答案時(shí)肯定的,方法可以從兩個(gè)方面入手:
方案一:函數(shù)傳參
方案二:改變函數(shù)執(zhí)行上下文
我們先來(lái)看方案一怎么實(shí)現(xiàn)的,以下是示例代碼:
var a='how are you';
function ab(a){
? ? ? console.log('a=',a);
}
function ac(){
? ? ? var a="I'm fine";
? ? ? ab(a);
}
ab(a);
ac(a);
輸出:

通過(guò)輸出可以看出函數(shù)ab的輸出發(fā)生了改變,這是因?yàn)樵诤瘮?shù)ac中變量a被當(dāng)作參數(shù)傳入了函數(shù)ab。再看函數(shù)ac的寫(xiě)法是不是很熟悉,這就是常見(jiàn)的回調(diào)函數(shù)的寫(xiě)法,回調(diào)函數(shù)在異步j(luò)avascript應(yīng)用很多。在函數(shù)ac中函數(shù)ab的調(diào)用,嚴(yán)格意義上算不上閉包,因?yàn)閍c只調(diào)用了ab本身,沒(méi)有連ab外的變量一起調(diào)用。
我們?cè)賮?lái)看改變函數(shù)執(zhí)行上下文怎么實(shí)現(xiàn):
var x="how are you";
function ab(){
? ? ? console.log("x=",this.x);
}
var a={
? ? ? x:"i'm fine"
};
ab();
ab.call(a);
以下是輸出結(jié)果:

ab的輸出更改成功,?在js中使用call,apply以及bind這些方法可以改變函數(shù)執(zhí)行的上下文。
總結(jié),js中的閉包如果想通了其實(shí)很簡(jiǎn)單,就是一個(gè)函數(shù)如果被調(diào)用的話,它不是在調(diào)用它的作用域執(zhí)行的,而是在定義函數(shù)的作用域執(zhí)行的。理論上在不改變函數(shù)執(zhí)行上下文的情況下,只有定義函數(shù)的作用域以及函數(shù)內(nèi)部作用域可以影響函數(shù)的輸出,調(diào)用函數(shù)的作用域要想影響函數(shù)的輸出,只有三個(gè)方法,第一個(gè)調(diào)用函數(shù)作用域以及定義函數(shù)作用域是同一個(gè)作用域(這個(gè)純屬扯淡,是個(gè)人都知道),第二個(gè)是調(diào)用函數(shù)作用域?qū)?shù)傳進(jìn)函數(shù)內(nèi)部作用域,第三個(gè)是通過(guò)apply,call以及bind這些方法改變函數(shù)執(zhí)行的上下文。我現(xiàn)在還想到了第四個(gè)方法,時(shí)間有限,不說(shuō)了,以后在補(bǔ)充。
第一次寫(xiě)技術(shù)文章,難免有很多遺漏的地方,如果這篇文章能有幸給人看到的話,希望您能留下寶貴的意見(jiàn)。