js 閉包

一擦盾、什么是閉包?

“官方”的解釋是:所謂“閉包”写半,指的是一個(gè)擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個(gè)函數(shù))又碌,因而這些變量也是該表達(dá)式的一部分九昧。

相信很少有人能直接看懂這句話绊袋,因?yàn)樗枋龅奶珜W(xué)術(shù)。我想用如何在Javascript中創(chuàng)建一個(gè)閉包來告訴你什么是閉包铸鹰,因?yàn)樘^閉包的創(chuàng)建過程直接理解閉包的定義是非常困難的癌别。看下面這段代碼:

function a(){

var i=0;

function b(){

alert(++i);

}

return b;

}

var c = a();

c();

這段代碼有兩個(gè)特點(diǎn):

1蹋笼、函數(shù)b嵌套在函數(shù)a內(nèi)部展姐;

2、函數(shù)a返回函數(shù)b剖毯。

這樣在執(zhí)行完var c=a()后圾笨,變量c實(shí)際上是指向了函數(shù)b,再執(zhí)行c()后就會(huì)彈出一個(gè)窗口顯示i的值(第一次為1)逊谋。這段代碼其實(shí)就創(chuàng)建了一個(gè)閉包擂达,為什么?因?yàn)楹瘮?shù)a外的變量c引用了函數(shù)a內(nèi)的函數(shù)b胶滋,就是說:

當(dāng)函數(shù)a的內(nèi)部函數(shù)b被函數(shù)a外的一個(gè)變量引用的時(shí)候板鬓,就創(chuàng)建了一個(gè)閉包。

我猜想你一定還是不理解閉包究恤,因?yàn)槟悴恢篱]包有什么作用俭令,下面讓我們繼續(xù)探索。

二丁溅、閉包有什么作用唤蔗?

簡而言之探遵,閉包的作用就是在a執(zhí)行完并返回后窟赏,閉包使得Javascript的垃圾回收機(jī)制GC不會(huì)收回a所占用的資源,因?yàn)閍的內(nèi)部函數(shù)b的執(zhí)行需要依賴a中的變量箱季。這是對閉包作用的非常直白的描述涯穷,不專業(yè)也不嚴(yán)謹(jǐn),但大概意思就是這樣藏雏,理解閉包需要循序漸進(jìn)的過程拷况。

在上面的例子中,由于閉包的存在使得函數(shù)a返回后掘殴,a中的i始終存在赚瘦,這樣每次執(zhí)行c(),i都是自加1后alert出i的值奏寨。

那 么我們來想象另一種情況起意,如果a返回的不是函數(shù)b,情況就完全不同了病瞳。因?yàn)閍執(zhí)行完后揽咕,b沒有被返回給a的外界悲酷,只是被a所引用,而此時(shí)a也只會(huì)被b引 用亲善,因此函數(shù)a和b互相引用但又不被外界打擾(被外界引用)设易,函數(shù)a和b就會(huì)被GC回收。(關(guān)于Javascript的垃圾回收機(jī)制將在后面詳細(xì)介紹)

三蛹头、閉包內(nèi)的微觀世界

如 果要更加深入的了解閉包以及函數(shù)a和嵌套函數(shù)b的關(guān)系顿肺,我們需要引入另外幾個(gè)概念:函數(shù)的執(zhí)行環(huán)境(excution context)、活動(dòng)對象(call object)掘而、作用域(scope)挟冠、作用域鏈(scope chain)。以函數(shù)a從定義到執(zhí)行的過程為例闡述這幾個(gè)概念袍睡。

1知染、當(dāng)定義函數(shù)a的時(shí)候,js解釋器會(huì)將函數(shù)a的作用域鏈(scope chain)設(shè)置為定義a時(shí)a所在的“環(huán)境”斑胜,如果a是一個(gè)全局函數(shù)控淡,則scope chain中只有window對象。

2止潘、當(dāng)函數(shù)a執(zhí)行的時(shí)候掺炭,a會(huì)進(jìn)入相應(yīng)的執(zhí)行環(huán)境(excution context)。

3凭戴、在創(chuàng)建執(zhí)行環(huán)境的過程中涧狮,首先會(huì)為a添加一個(gè)scope屬性,即a的作用域么夫,其值就為第1步中的scope chain者冤。即a.scope=a的作用域鏈。

4档痪、然后執(zhí)行環(huán)境會(huì)創(chuàng)建一個(gè)活動(dòng)對象(call object)涉枫。活動(dòng)對象也是一個(gè)擁有屬性的對象腐螟,但它不具有原型而且不能通過JavaScript代碼直接訪問愿汰。創(chuàng)建完活動(dòng)對象后,把活動(dòng)對象添加到a的作用域鏈的最頂端乐纸。此時(shí)a的作用域鏈包含了兩個(gè)對象:a的活動(dòng)對象和window對象衬廷。

5、下一步是在活動(dòng)對象上添加一個(gè)arguments屬性汽绢,它保存著調(diào)用函數(shù)a時(shí)所傳遞的參數(shù)吗跋。

6、最后把所有函數(shù)a的形參和內(nèi)部的函數(shù)b的引用也添加到a的活動(dòng)對象上庶喜。在這一步中小腊,完成了函數(shù)b的的定義救鲤,因此如同第3步,函數(shù)b的作用域鏈被設(shè)置為b所被定義的環(huán)境秩冈,即a的作用域本缠。

到此,整個(gè)函數(shù)a從定義到執(zhí)行的步驟就完成了入问。此時(shí)a返回函數(shù)b的引用給c丹锹,又函數(shù)b的作用域鏈包含了對函數(shù)a的活動(dòng)對象的引用,也就是說b可以訪問到a中定義的所有變量和函數(shù)芬失。函數(shù)b被c引用楣黍,函數(shù)b又依賴函數(shù)a,因此函數(shù)a在返回后不會(huì)被GC回收棱烂。

當(dāng)函數(shù)b執(zhí)行的時(shí)候亦會(huì)像以上步驟一樣租漂。因此,執(zhí)行時(shí)b的作用域鏈包含了3個(gè)對象:b的活動(dòng)對象颊糜、a的活動(dòng)對象和window對象哩治,如下圖所示:

如圖所示,當(dāng)在函數(shù)b中訪問一個(gè)變量的時(shí)候衬鱼,搜索順序是先搜索自身的活動(dòng)對象业筏,如果存在則返回,如果不存在將繼續(xù)搜索函數(shù)a的活動(dòng)對象鸟赫,依 次查找蒜胖,直到找到為止。如果整個(gè)作用域鏈上都無法找到抛蚤,則返回undefined台谢。如果函數(shù)b存在prototype原型對象,則在查找完自身的活動(dòng)對象 后先查找自身的原型對象霉颠,再繼續(xù)查找对碌。這就是Javascript中的變量查找機(jī)制荆虱。

四蒿偎、閉包的應(yīng)用場景

1、保護(hù)函數(shù)內(nèi)的變量安全怀读。以最開始的例子為例诉位,函數(shù)a中i只有函數(shù)b才能訪問,而無法通過其他途徑訪問到菜枷,因此保護(hù)了i的安全性苍糠。

2、在內(nèi)存中維持一個(gè)變量啤誊。依然如前例岳瞭,由于閉包拥娄,函數(shù)a中i的一直存在于內(nèi)存中,因此每次執(zhí)行c()瞳筏,都會(huì)給i自加1稚瘾。

以上兩點(diǎn)是閉包最基本的應(yīng)用場景,很多經(jīng)典案例都源于此姚炕。

五摊欠、閉包的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):?

1.保護(hù)函數(shù)內(nèi)的變量安全,加強(qiáng)了封裝性?

2.在內(nèi)存中維持一個(gè)變量(用的太多就變成了缺點(diǎn),占內(nèi)存)?

閉包之所以會(huì)占用資源是當(dāng)函數(shù)a執(zhí)行結(jié)束后, 變量i不會(huì)因?yàn)楹瘮?shù)a的結(jié)束而銷毀, 因?yàn)閎的執(zhí)行需要依賴a中的變量柱宦。

缺點(diǎn):

閉包有一個(gè)非常嚴(yán)重的問題些椒,那就是內(nèi)存浪費(fèi)問題,這個(gè)內(nèi)存浪費(fèi)不僅僅因?yàn)樗qv內(nèi)存掸刊,更重要的是免糕,對閉包的使用不當(dāng)會(huì)造成無效內(nèi)存的產(chǎn)生

五、Javascript的垃圾回收機(jī)制

在Javascript中忧侧,如果一個(gè)對象不再被引用说墨,那么這個(gè)對象就會(huì)被GC回收。如果兩個(gè)對象互相引用苍柏,而不再被第3者所引用尼斧,那么這兩個(gè)互相引用的對象也會(huì)被回收。因?yàn)楹瘮?shù)a被b引用试吁,b又被a外的c引用棺棵,這就是為什么函數(shù)a執(zhí)行后不會(huì)被回收的原因。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末熄捍,一起剝皮案震驚了整個(gè)濱河市烛恤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌余耽,老刑警劉巖缚柏,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異碟贾,居然都是意外死亡币喧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門袱耽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來杀餐,“玉大人,你說我怎么就攤上這事朱巨∈非蹋” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長琼讽。 經(jīng)常有香客問我必峰,道長,這世上最難降的妖魔是什么钻蹬? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任自点,我火速辦了婚禮,結(jié)果婚禮上脉让,老公的妹妹穿的比我還像新娘桂敛。我一直安慰自己,他們只是感情好溅潜,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布术唬。 她就那樣靜靜地躺著,像睡著了一般滚澜。 火紅的嫁衣襯著肌膚如雪粗仓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天设捐,我揣著相機(jī)與錄音借浊,去河邊找鬼。 笑死萝招,一個(gè)胖子當(dāng)著我的面吹牛蚂斤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播槐沼,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼曙蒸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了岗钩?” 一聲冷哼從身側(cè)響起纽窟,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎兼吓,沒想到半個(gè)月后臂港,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡视搏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年审孽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凶朗。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瓷胧,死狀恐怖显拳,靈堂內(nèi)的尸體忽然破棺而出棚愤,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布宛畦,位于F島的核電站瘸洛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏次和。R本人自食惡果不足惜反肋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望踏施。 院中可真熱鬧石蔗,春花似錦、人聲如沸畅形。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽日熬。三九已至棍厌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間竖席,已是汗流浹背耘纱。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留毕荐,地道東北人束析。 一個(gè)月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像憎亚,于是被迫代替她去往敵國和親畸陡。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

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

  • 閉包: 官方”的解釋是:閉包是一個(gè)擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個(gè)函數(shù))虽填,因而這些變量也是該...
    小裁縫sun閱讀 610評論 0 5
  • 談起閉包斋日,它可是JavaScript兩個(gè)核心技術(shù)之一(異步和閉包),在面試以及實(shí)際應(yīng)用當(dāng)中牲览,我們都離不開它們,甚至...
    sponing閱讀 677評論 0 7
  • 閉包(closure)是Javascript語言的一個(gè)難點(diǎn)恶守,也是它的特色第献,很多高級應(yīng)用都要依靠閉包實(shí)現(xiàn)。 一兔港、變量...
    zock閱讀 1,075評論 2 6
  • 常量 常量定義 常量使用關(guān)鍵字 const 定義庸毫,用于存儲不會(huì)改變的數(shù)據(jù),在GO語言中衫樊,常量只能布爾型飒赃,數(shù)字型利花,和...
    astarblog閱讀 290評論 0 0
  • 家有警察 有幾天恋拷,我連續(xù)上網(wǎng)到很晚艰亮。女兒對我提出批評。我辯解:只一個(gè)小時(shí)多一點(diǎn)娃圆∧杌郏“不止吧挠乳。”女兒不依不饒姑躲。眼睛都紅...
    福在平安閱讀 198評論 1 2