javascript
彻底了解JS中难懂的闭包
來自:一只有趣的程序猿?|?責(zé)編:樂樂
鏈接:jianshu.com/p/2fa4e8a1eaf9
閉包的定義
閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)。(JS高級程序設(shè)計)
看到這紅寶書上關(guān)于閉包的解釋,起初一臉懵逼,讀懂之后其實并不難。
要徹底了解閉包,首先必須了解下面的幾個概念:
執(zhí)行環(huán)境:每個函數(shù)都有自己的執(zhí)行環(huán)境。當(dāng)執(zhí)行函數(shù)時,函數(shù)的環(huán)境就會被推入一個環(huán)境棧中。而在函數(shù)執(zhí)行后,棧將其環(huán)境彈出,把控制權(quán)返回給之前的執(zhí)行環(huán)境。
變量對象:每個執(zhí)行環(huán)境都有一個與之關(guān)聯(lián)的變量對象,環(huán)境中定義的所有變量和函數(shù)都保存在這個對象中。當(dāng)執(zhí)行函數(shù)時,變量對象會變成活動對象。
作用域鏈:當(dāng)代碼在一個環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈。作用域鏈的用途,是保證對執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問。作用域鏈的前端,始終都是當(dāng)前執(zhí)行的代碼所
在環(huán)境的變量對象。如果這個環(huán)境是函數(shù),則將其活動對象作為變量對象。
執(zhí)行環(huán)境和變量對象的概念容易理解,但是怎么理解作用域鏈呢。可以參考下圖:
理解作用域鏈
可以看成是同心圓結(jié)構(gòu),每一層假設(shè)是一個函數(shù),上面都擁有與此層函數(shù)關(guān)聯(lián)的變量對象;假設(shè)當(dāng)執(zhí)行到最里面那個函數(shù),那么作用域鏈可以看做是圖中一條由內(nèi)到外的線,最前端的就是它本身,最后端就是全局執(zhí)行環(huán)境。
那么它有什么用呢,就是當(dāng)你訪問一個變量的時候,就會沿著作用域鏈一層層往外查找,直到找到為止,如果到了最外層即全局執(zhí)行環(huán)境下還沒找到則報錯。
閉包的實現(xiàn)
下面通過具體例子來解釋:
function?a()?{var?text?=?'呵呵噠';return?function?()?{console.log(text);} } var?b?=?a(); b();當(dāng)a()函數(shù)被執(zhí)行后返回了一個匿名函數(shù),這個匿名函數(shù)的作用域鏈上有引用到a()執(zhí)行環(huán)境的活動對象屬性text(不知道活動對象是什么的請看上面變量對象的解釋)。
a()函數(shù)執(zhí)行完就馬上被銷毀了,但是這個函數(shù)的變量對象仍然被b所引用,所以它的變量對象不會被垃圾回收機制處理掉,而是會留在內(nèi)存中。這就形成了一個閉包。最后執(zhí)行b()依然能讀取到已經(jīng)被銷毀的a函數(shù)的定義的text變量。
我們換個更清晰的例子:
function?a()?{var?i?=?0;return?function?()?{console.log(i++);} } var?b?=?a(); b();????//0 b();????//1 b();????//2這個例子三次調(diào)用b()會分別輸出0、 1、 2,是因為a()的變量對象被return的閉包函數(shù)引用著,所以i會一直留在內(nèi)存中,并只能被閉包函數(shù)所訪問。這個閉包函數(shù)被賦值給了b,所以b()能對i變量進行自增計算。
閉包的作用
什么,你問我閉包有什么用?
好處就是隱藏變量,然后搭起一條溝通的橋,閉包可以間接操作這個隱藏變量;并且讓這個變量留在內(nèi)存中而不會污染到全局變量。
壞處呢消耗內(nèi)存,如果一直不釋放這個閉包就會一直占用著內(nèi)存。那要怎么釋放呢?很簡單,和函數(shù)一樣賦值null就可以了。(b = null)
總結(jié)
以上是生活随笔為你收集整理的彻底了解JS中难懂的闭包的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 同步IO和异步IO的理解
- 下一篇: 【最新最全】JavaScript从入门到