JS閉包 - 先說基礎(chǔ)

我最初對(duì)閉包的定義

關(guān)于閉包颓鲜,很多地方都有所謂的標(biāo)準(zhǔn)定義孽水;但我相信很多人和我一樣尊浪,看了標(biāo)準(zhǔn)定義之后就進(jìn)入了蒙B狀態(tài)匣屡。下面是我給出的定義;

閉:封閉
包:作用域
閉包:封閉的作用域

我知道看完我的定義你一樣進(jìn)入到了蒙B狀態(tài)拇涤,但是沒關(guān)系捣作,且聽我慢慢道來。

你一定想問我鹅士,是不是只要有一個(gè)封閉的作為域就能形成閉包呢券躁?我很想說Yes,但是我不能如绸。因?yàn)槭遣皇情]包嘱朽,還需要看它能否表現(xiàn)出閉包的特性。

關(guān)于閉包的特性怔接,在基礎(chǔ)里是說不完的搪泳,稍候我會(huì)列舉幾個(gè)閉包基本的特性;關(guān)于閉包特性的全面分析扼脐,我會(huì)再出專門的文章來講述我的理解岸军。

說閉包,就必須說清楚它所處的語(yǔ)言環(huán)境瓦侮,在不同的語(yǔ)言環(huán)境下艰赞,閉包的特性是不完全一樣的。所以我定的標(biāo)題是JS閉包肚吏,在javascript語(yǔ)言環(huán)境下的閉包方妖。

看了對(duì)閉包的標(biāo)準(zhǔn)定義后我的疑問

現(xiàn)在,不得不引用一些標(biāo)準(zhǔn)定義罚攀,來簡(jiǎn)化我的表達(dá):

MDN官方解釋:

Closures are functions that refer to independent (free) variables (variables that are used locally, but defined in an enclosing scope). In other words, these functions 'remember' the environment in which they were created.

我的翻譯:

Closures 就是一個(gè)關(guān)聯(lián)了“獨(dú)立(自由)變量”(這些變量在封閉的作用域內(nèi)定義党觅,并且只能在這個(gè)封閉的作用域內(nèi)使用)的函數(shù)雌澄;也就是說,作為閉包的函數(shù)記住了創(chuàng)建他們的上下文環(huán)境杯瞻。

關(guān)于這個(gè)定義是否準(zhǔn)確镐牺,在此我先不發(fā)表意見,但對(duì)于以上定義魁莉,我有以下疑問:

  1. 什么叫獨(dú)立變量或自由變量睬涧?
  2. 怎么記住的?
  3. 變量只能在封閉的作用域內(nèi)使用旗唁,這個(gè)封閉的作用域與閉包是什么關(guān)系畦浓?

并且我相信很多人與我一樣,有這些疑問逆皮。接下來我就一一解釋這些疑問宅粥,當(dāng)所有的疑問被消除后参袱,你應(yīng)該就能對(duì)閉包有一個(gè)基本的認(rèn)知了电谣。

上面的英文在括號(hào)中有對(duì)“獨(dú)立(自由)變量”進(jìn)行解釋說明,但這句話非常具有誤導(dǎo)性抹蚀,想要真正理解閉包剿牺,你必須忘了它。

通過其他版本的閉包定義消除第一層疑問

好环壤,我們?cè)賮砜纯聪露鴣碜杂凇氨貞?yīng)網(wǎng)典”對(duì)閉包的定義:

閉包是指可以包含自由(未綁定到特定對(duì)象)變量的代碼塊晒来;這些變量不是在這個(gè)代碼塊內(nèi)或者任何全局上下文中定義的,而是在定義代碼塊的環(huán)境中定義(局部變量)郑现∨缺溃“閉包” 一詞來源于以下兩者的結(jié)合:要執(zhí)行的代碼塊(由于自由變量被包含在代碼塊中,這些自由變量以及它們引用的對(duì)象沒有被釋放)和為自由變量提供綁定的計(jì)算環(huán)境(作用域)接箫。

通過上面這段來自于必應(yīng)網(wǎng)典的定義攒读,我們可以把上面的第一個(gè)疑問消除了。下面給出我的理解:

獨(dú)立(自由)變量:

  1. 首先是未綁定到特定的對(duì)象辛友,也就是無(wú)法使用 obj.attr 的方式訪問到的變量薄扁。(obj是一個(gè)對(duì)象,而attr是獨(dú)立變量的變量名)
  2. 不是在這個(gè)代碼塊內(nèi)或者全局上下文件中定義的废累,而是在定義代碼塊的環(huán)境中定義的局部變量邓梅。

如果你對(duì)“什么是綁定到特定對(duì)象”不了解,你可以去看一下JS中是如何支持面向?qū)ο蟮囊乇酰嘈拍憧赐旰髸?huì)明白“什么是綁定到特定的對(duì)象”日缨。

我相信有人會(huì)問,上面 2 中提到的“代碼塊”是什么掖看?其實(shí)我最初讀“必應(yīng)網(wǎng)典”上的這段文字時(shí)也有同樣的疑問匣距。

請(qǐng)?jiān)僮x一遍必應(yīng)網(wǎng)典上的定義閉包的那段話吧诈铛,第一句:

閉包是指可以包含自由(未綁定到特定對(duì)象)變量的“代碼塊”

然后繼續(xù)往下讀……墨礁,是不是明白了幢竹,這段話中的“代碼塊”其實(shí)就是指閉包。那我們把“代碼塊”三個(gè)字換成“閉包”然后再來讀一下 2 里面的話:

不是在這個(gè)“閉包”內(nèi)或者全局上下文件中定義的恩静,而是在定義“閉包”的環(huán)境中定義的局部變量焕毫。

什么是“局部變量”我就不再解釋了,如果你不懂,那么請(qǐng)放棄編程驶乾;經(jīng)過以上分析我們對(duì)“獨(dú)立(自由)變量”的含意已經(jīng)非常清楚了邑飒。下面再重寫一遍,加深印象级乐。

獨(dú)立(自由)變量:

  1. 首先是未綁定到特定的對(duì)象
  2. 不是在這個(gè)“閉包”內(nèi)或者全局上下文件中定義的疙咸,而是在定義“閉包”的環(huán)境中定義的局部變量。

通過分析推理消除第二層疑問

好了风科,疑問一已經(jīng)消除撒轮,那就向疑問二進(jìn)軍吧。先看一段閉包的代碼:

function ClosuresOuter(){
  var random = Math.random();
  function ClosuresInner(){
    return random
  }
  return ClosuresInner;
} 
Closures = ClosuresOuter();

請(qǐng)仔細(xì)思考后告訴我贼穆,上面這段代碼中题山,誰(shuí)是閉包?

我知道有人說 ClosuresOuter 是閉包故痊,也有人說 ClosuresInner 是閉包顶瞳;這樣理解也不能說是錯(cuò),但真正意義上的閉包應(yīng)該是上述代碼中的 Closures 愕秫,通過調(diào)用 ClosuresOuter 返回的函數(shù)慨菱。

有爭(zhēng)議,沒關(guān)系戴甩,我們先不討論誰(shuí)才是真正意義上的閉包符喝,我們回到最初的目的,解決疑問二:閉包是如何記住獨(dú)立(自由)變量的等恐?

不過要先確認(rèn)一點(diǎn)洲劣,所有人都認(rèn)同以上代碼中是創(chuàng)建了閉包的。如果你覺得上述代碼沒有創(chuàng)建閉包课蔬,那么請(qǐng)回避囱稽。

在函數(shù)內(nèi)可以訪問函數(shù)外聲明的變量,看上面的代碼二跋,ClosuresInner 內(nèi)部使用了在 ClosuresInner 外部定義的變量 random 战惊,所以如果ClosuresInner 是閉包的話,它就是這樣記住“獨(dú)立(自由)變量”的扎即。

在javascript中吞获,上面代碼中的ClosuresInner 不僅記住了 random况凉, 還記住了運(yùn)行函數(shù) ClosuresOuter 所創(chuàng)建的整個(gè)環(huán)境,這是javascript的語(yǔ)言特性各拷,也是javascript支持閉包特性的前提條件刁绒。

現(xiàn)在疑問二告破;

究竟誰(shuí)是閉包烤黍?

在上一節(jié)的代碼中知市,random 是否滿足“獨(dú)立(自由)變量”的條件呢?

  1. 首先這個(gè)變量沒有綁定到任何對(duì)象
  2. 然后這個(gè)變量不能在閉包內(nèi)或全局作用域內(nèi)定義速蕊,需要在定義閉包的作用域內(nèi)定義嫂丙。

好吧,ClosuresOuter 已經(jīng)不可能是閉包了规哲。有些認(rèn)為ClosuresInner是閉包的同學(xué)們是不是開始洋洋得意跟啤,沾沾自喜了?不要這樣唉锌,請(qǐng)往下看隅肥。

實(shí)驗(yàn)截圖

請(qǐng)仔細(xì)看上面的“實(shí)驗(yàn)截圖”,ClosureOuter 就是上面代碼中定義的那個(gè)糊秆。每次運(yùn)行 ClosureOuter 都會(huì)產(chǎn)生一個(gè)新的 random ,請(qǐng)問是誰(shuí)記住了random武福?答案是 ClosureInner,但也不是痘番。原因是,每次運(yùn)行ClosureOuter 同樣會(huì)產(chǎn)生一個(gè)新的 ClosureInner平痰。

這樣說吧汞舱,ClosureInner其實(shí)并不存在,它只是ClosureOuter 作用域內(nèi)的一個(gè)局部變量(函數(shù))宗雇;如果這個(gè)ClosureInner沒有被 ClosureOuter 返回并被外層接收返回值的變量接收的話昂芜,這個(gè)ClosureOuter 運(yùn)行所創(chuàng)建的臨時(shí)作用域和作用域內(nèi)的變量(包含 random 和ClosureInner)會(huì)很快被垃圾回收器收回。

所以結(jié)論是 ClosureOuter 返回的函數(shù)才是閉包(也就是上述代碼中的 Closure)赔蒲。

閉包的基本特性

這個(gè)小節(jié)只是為了履行前方的承諾泌神,所以不打算用心寫,見諒舞虱!

  1. 記住閉包所在的環(huán)境欢际;創(chuàng)建閉包的外層函數(shù)運(yùn)行時(shí)所創(chuàng)建的環(huán)境不會(huì)被垃圾回收,只有這樣才能讓閉包記住它所在的環(huán)境以及該環(huán)境內(nèi)的獨(dú)立(自由)變量矾兜;所以使用閉包有得有失啊损趋。

自圓其說

最開始我對(duì)閉包的定義是:封閉的作用域。這明顯很不靠譜啊椅寺。所以現(xiàn)在細(xì)化如下:

閉:封閉
包:作用域浑槽,環(huán)境
閉包:能夠記憶被創(chuàng)建時(shí)環(huán)境的封閉作用域

好了蒋失,也是址淡的定義,初學(xué)者看后也只能蒙了一B桐玻。

我為什么不說閉包是“函數(shù)”篙挽,而是說成“作用域”

簡(jiǎn)單了說,是因?yàn)槲抑纉ava的“內(nèi)部類”也是一種閉包镊靴。

裝B一點(diǎn)的說法是:只要能夠表現(xiàn)出閉包的特性嫉髓,就可以稱之為閉包。在javascript中只有函數(shù)有自己的作用域邑闲,所以也只有函數(shù)有條件成為閉包算行。但在其他語(yǔ)言中有很多擁有自己作用域的概念,如:包苫耸,類州邢,一個(gè)代碼塊都可以有自己的作用域。所以把說成是擁有閉包特性的函數(shù)也只在javascript語(yǔ)言中成立褪子。

總結(jié)

之所以有這個(gè)小節(jié)量淌,是我的一種習(xí)慣。
閉包基礎(chǔ)就寫到這兒吧嫌褪。有不同的見解的呀枢,歡迎吐槽。

為什么不解釋疑問三

我都說了這句話:“這些變量在封閉的作用域內(nèi)定義笼痛,并且只能在這個(gè)封閉的作用域內(nèi)使用”裙秋,非常具有誤導(dǎo)性,想要真正理解閉包缨伊,你必須忘了它摘刑。你為什么不聽呢?哼刻坊!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末枷恕,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谭胚,更是在濱河造成了極大的恐慌徐块,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灾而,死亡現(xiàn)場(chǎng)離奇詭異胡控,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)绰疤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門铜犬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事癣猾×踩埃” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵纷宇,是天一觀的道長(zhǎng)夸盟。 經(jīng)常有香客問我,道長(zhǎng)像捶,這世上最難降的妖魔是什么上陕? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮拓春,結(jié)果婚禮上释簿,老公的妹妹穿的比我還像新娘。我一直安慰自己硼莽,他們只是感情好庶溶,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著懂鸵,像睡著了一般偏螺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上匆光,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天套像,我揣著相機(jī)與錄音,去河邊找鬼终息。 笑死夺巩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的采幌。 我是一名探鬼主播劲够,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼休傍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蹲姐,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤磨取,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后柴墩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忙厌,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年江咳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了逢净。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖爹土,靈堂內(nèi)的尸體忽然破棺而出甥雕,到底是詐尸還是另有隱情,我是刑警寧澤胀茵,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布社露,位于F島的核電站,受9級(jí)特大地震影響琼娘,放射性物質(zhì)發(fā)生泄漏峭弟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一脱拼、第九天 我趴在偏房一處隱蔽的房頂上張望瞒瘸。 院中可真熱鬧,春花似錦熄浓、人聲如沸情臭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)谎柄。三九已至,卻和暖如春惯雳,著一層夾襖步出監(jiān)牢的瞬間朝巫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工石景, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劈猿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓潮孽,卻偏偏與公主長(zhǎng)得像揪荣,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子往史,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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