js中的閉包
閉包是學(xué)習(xí)js中永遠(yuǎn)也繞不過去的一個(gè)坎肩钠,那么慈缔,今天我們就去一段簡(jiǎn)單的代碼開始聊一聊閉包
什么是閉包
這個(gè)概念性的東西翻譯有很多種,純官方的翻譯比較晦澀難懂漠畜,我們把它理解成一個(gè)比較特殊的函數(shù)就行秀睛。按照網(wǎng)上的說法來說就是:
「函數(shù)」和「函數(shù)內(nèi)部能訪問到的變量」(也叫環(huán)境)的總和尔当,就是一個(gè)閉包。
function close(){
????varn=999;
????var getNumber=function(){
????????return n;? ? ? ??
????};
????return getNumber;? ??
}
在close函數(shù)里面有一個(gè)getNumber方法蹂安,通過getNumber方法可以訪問到函數(shù)的內(nèi)部變量椭迎。
閉包的特性
能夠讀取函數(shù)內(nèi)部的變量
能讓這些變量的值始終保持在內(nèi)存中
第一點(diǎn)很好理解,我們平時(shí)可能在不知不覺中就使用了閉包的這個(gè)特性田盈,而第二點(diǎn)雖然用的不多畜号,但是在面試中經(jīng)常遇到。首先我們先看一段代碼:
function f1(){
????varn=999; ? ? ??
????nAdd=function(){
? ? ? ? ? ? n++;
? ? ? ? };
????function f2(){
????????console.log(n);
? ? ? ? }
????????return f2;
? ? }
var result=f1();
?result();//999
?nAdd();? ??
? result();//1000
為什么第二次執(zhí)行后打印的結(jié)果是1000允瞧,而不是999简软,因?yàn)閚被保存下來了驰怎,并沒有被內(nèi)存回收機(jī)制回收垦垂。
為什么每有被回收娩鹉?因?yàn)閒1是f2的父函數(shù)典蜕,而f2被賦給了一個(gè)全局變量,這導(dǎo)致f2始終在內(nèi)存中疼蛾,而f2的存在依賴于f1踱卵,因此f1也始終在內(nèi)存中,不會(huì)在調(diào)用結(jié)束后据过,被垃圾回收機(jī)制(garbage collection)回收。
面試題解讀
這是一個(gè)很常見的閉包面試題:
varresult=[ ];
function foo(){
????vari=0;for(;i<3;i=i+1){?
?? ? ? ? ? result[i]=function(){
? ? ? ? ? ? ? ? alert(i);
? ? ? ? ? ? }?
?? ? ? }
? ? }
foo();? ?
result[0]( );// 3
result[1]( );// 3
result[2]( );// 3
運(yùn)行結(jié)果為什么是3妒挎,我簡(jiǎn)單的重現(xiàn)一下代碼運(yùn)行的過程绳锅,
i=0;result[0]=function(){alert(i)};
i=1;result[1]=function(){alert(i)};
i=2;result[2]=function(){alert(i)};
運(yùn)行的時(shí)候在function內(nèi)部放的是一個(gè)變量i,只有被執(zhí)行的時(shí)候才會(huì)給這個(gè)i賦值酝掩。當(dāng)執(zhí)行result[0]的時(shí)候鳞芙,里面的變量i因?yàn)樵诋?dāng)前作用域下并沒有被定義,所以向它的父級(jí)去找期虾,此時(shí)for循環(huán)已經(jīng)執(zhí)行完畢原朝,i的值是3,所以彈出的都是3镶苞。為什么i保存下來了喳坠,因?yàn)閞esult函數(shù)依賴于foo函數(shù),所以foo一直在內(nèi)存中茂蚓,i變量也沒有被內(nèi)存回收機(jī)制回收壕鹉。
那么如何實(shí)現(xiàn)彈出的是0,1聋涨,2呢晾浴?
利用之前提到的閉包就可以了,代碼如下:
varresult=[ ];function foo(){
????var i=0;
????for(;i<3;i=i+1){?
?? ? ? ? ? (function(){
????????????????var index=i;
? ? ? ? ? ? ? ? result[i]=function(){
? ? ? ? ? ? ? ? ? ? alert(index);?
?? ? ? ? ? ? ? }
? ? ? ? ? ? })()?
?? ? ? }
? ? }
foo(); ??
result[0]();// 0
result[1]();// 1
result[2]();// 2
利用立即執(zhí)行函數(shù)(IIF)牍白,我們可以創(chuàng)建一個(gè)閉包脊凰,在這個(gè)IIF內(nèi)部,我們使用index將i給保存下來了茂腥。具體執(zhí)行過程如下:
i=0;
(function(){
????var index=0;
? ? result[0]=function(){
? ? ? ? alert(index);
? ? }})()
i=1;
(function(){
????var index=1;
? ? result[1]=function(){
? ? ? ? alert(index);
? ? }})()
i=2;
(function(){
????varindex=2;
? ? result[2]=function(){
? ? ? ? alert(index);
? ? }})()
因?yàn)檫@些語(yǔ)句都放在IIF中狸涌,所以都有各自的作用域,index并不會(huì)重復(fù)础芍。就像下方的代碼:
var sayHi=function(){
????var words="hi"
}
var sayHello=function(){
????var words="hello"
}
兩個(gè)方法中雖然都有words這個(gè)變量杈抢,但是因?yàn)樵诓煌暮瘮?shù)中,都有各自的作用域仑性,所以互不干擾惶楼。
參考文獻(xiàn)