快速理解js中的閉包

今天研究了一波js中的閉包,分享一下自己的理解。

一、變量的作用域

要理解閉包,首先必須理解Javascript特殊的變量作用域。

變量的作用域無非就是兩種:全局變量和局部變量。

Javascript語言的特殊之處,就在于函數(shù)內(nèi)部可以直接讀取全局變量;

另一方面,在函數(shù)外部自然無法讀取函數(shù)內(nèi)的局部變量。

二、如何從外部讀取局部變量?

出于種種原因,我們有時(shí)候需要得到函數(shù)內(nèi)的局部變量。但是,前面已經(jīng)說過了,正常情況下,這是辦不到的,只有通過變通方法才能實(shí)現(xiàn)。

先看一下如果在函數(shù)外部和內(nèi)部都定義一個(gè)變量,其結(jié)果是會(huì)什么:

當(dāng)全局變量和局部變量重名時(shí),局部變量會(huì)覆蓋全局變量:

window.onload=function(){

var abc=11;

function aa(){

var abc=111;

alert(abc);};

aa();};

彈出的則是111;

然后我們?cè)诤瘮?shù)的內(nèi)部,再定義一個(gè)函數(shù)。

function f1(){

n=999;

function f2(){

alert(n);// 999}}

在上面的代碼中,函數(shù)f2就被包括在函數(shù)f1內(nèi)部,這時(shí)f1內(nèi)部的所有局部變量,對(duì)f2都是可見的。但是反過來就不行,f2內(nèi)部的局部變量,對(duì)f1 就是不可見的。這就是Javascript語言特有的“鏈?zhǔn)阶饔糜颉苯Y(jié)構(gòu)(chain scope),

子對(duì)象會(huì)一級(jí)一級(jí)地向上尋找所有父對(duì)象的變量。所以,父對(duì)象的所有變量,對(duì)子對(duì)象都是可見的,反之則不成立。

既然f2可以讀取f1中的局部變量,那么只要把f2作為返回值,我們不就可以在f1外部讀取它的內(nèi)部變量了嗎!

function f1(){

n=999;

function f2(){

alert(n);}

return f2;}

var result=f1();

result();// 999

三、閉包的概念

上一節(jié)代碼中的f2函數(shù),就是閉包。

函數(shù)內(nèi)部能獲取全局變量,但是函數(shù)內(nèi)部的局部變量只能在這個(gè)函數(shù)本身使用;

但閉包就能實(shí)現(xiàn):在一個(gè)函數(shù)a外的另外一個(gè)變量b能調(diào)用到函數(shù)a里面的局部變量。這就是閉包的作用;

閉包就是一個(gè)函數(shù)a中包含著一個(gè)函數(shù)c,而另一個(gè)獨(dú)立的變量b能通過函數(shù)c調(diào)用函數(shù)a的局部變量,這個(gè)過程就形成閉包。

window.onload=function(){

function a(){

var i=0;

function c(){alert(++i);} ?;

return c;};

var b=a();

b();};

這樣就能獲得函數(shù)a中的局部變量。

四、閉包的用途

閉包可以用在許多地方。它的最大用處有兩個(gè),一個(gè)是前面提到的可以讀取函數(shù)內(nèi)部的變量,另一個(gè)就是讓這些變量的值始終保持在內(nèi)存中。

怎么來理解這句話呢?請(qǐng)看下面的代碼。

function f1(){

var n=999;

nAdd=function(){n+=1}

function f2(){

alert(n);}

return f2;}

var result=f1();

result();// 999

nAdd();

result();// 1000

在這段代碼中,result實(shí)際上就是閉包f2函數(shù)。它一共運(yùn)行了兩次,第一次的值是999,第二次的值是1000。這證明了,函數(shù)f1中的局部變量n一直保存在內(nèi)存中,并沒有在f1調(diào)用后被自動(dòng)清除。

為什么會(huì)這樣呢?原因就在于f1是f2的父函數(shù),而f2被賦給了一個(gè)全局變量,這導(dǎo)致f2始終在內(nèi)存中,而f2的存在依賴于f1,因此f1也始終在內(nèi)存中,不會(huì)在調(diào)用結(jié)束后,被垃圾回收機(jī)制(garbage collection)回收。

五、使用閉包的注意點(diǎn)

1)由于閉包會(huì)使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會(huì)造成網(wǎng)頁的性能問題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。

2)閉包會(huì)在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。所以,如果你把父函數(shù)當(dāng)作對(duì)象(object)使用,把閉包當(dāng)作它的公用方法(Public Method),把內(nèi)部變量當(dāng)作它的私有屬性(private value),這時(shí)一定要小心,不要隨便改變父函數(shù)內(nèi)部變量的值。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 閉包(closure)是Javascript語言的一個(gè)難點(diǎn),也是它的特色,很多高級(jí)應(yīng)用都要依靠閉包實(shí)現(xiàn)。 一、變量...
    zock閱讀 1,084評(píng)論 2 6
  • 閉包(closure)是Javascript語言的一個(gè)難點(diǎn),也是它的特色,很多高級(jí)應(yīng)用都要依靠閉包實(shí)現(xiàn)。 一、變量...
    zouCode閱讀 1,284評(píng)論 0 13
  • 一、變量的作用域 要理解閉包,首先必須理解Javascript特殊的變量作用域。 變量的作用域無非就是兩種:全局變...
    AlisaMfz閱讀 1,786評(píng)論 0 2
  • ● 閉包基礎(chǔ) ● 閉包作用 ● 閉包經(jīng)典例子 ● 閉包應(yīng)用 ● 閉包缺點(diǎn) ● 參考資料 1、閉包基礎(chǔ) 作用域和作...
    lzyuan閱讀 960評(píng)論 0 0
  • 黃山無夢(mèng)麗江愁, 半為癡心半為游。 了卻心頭無限事, 江山萬里一春秋。
    暮云平y(tǒng)m閱讀 584評(píng)論 3 51