JavaScript基礎(chǔ) 理解閉包
定義: 如果一個作用域可以訪問另外一個函數(shù)的局部變量,此時就形成了閉包。而被訪問變量的這個函數(shù)就是閉包。
理解閉包前,先看看自己是否理解以下幾點概念:
1.首先明確: 閉包是函數(shù)?。。?/p>
2.js的兩種數(shù)據(jù)類型:簡單數(shù)據(jù)類型(number,布爾,null,string ,undefined); ?復(fù)雜數(shù)據(jù)類型(對象,數(shù)組,函數(shù))。
問:這兩種數(shù)據(jù)類型如何區(qū)分出來的?
答: 其根本原因是在內(nèi)存中的存儲方式不同!
簡單數(shù)據(jù)類型直接存儲在棧中,比如: var i = 10; 10這個值存放在棧中,代碼運行時直接就可以拿到。
復(fù)雜數(shù)據(jù)類型的值存儲在堆中,棧中存放的是指向堆中數(shù)據(jù)的地址。
比如: var a = { n: 100}; ?代碼運行時,在棧中實際存放的是 a = AABBBFFF123 的一串指向堆的地址,而真正的值 n: 100 ,是存放在堆中的。調(diào)用 對象a 時,實質(zhì)上是依靠棧中存儲的這段地址,去引用堆中的值。

3.js代碼的垃圾回收及內(nèi)存管理:
局部作用函數(shù)的局部變量,只在局部作用域可以訪問。
全局作用域的變量,無論全局還是局部,都可以訪問。
當期嵌套的作用域鏈的其他函數(shù)的變量和參數(shù)。(這就是閉包的實現(xiàn)原理)
以上3種情況下,其存儲變量和參數(shù)的內(nèi)存空間都不回收。
舉個例子:?
function fn() {
? ? ?var i = 10;
}
fn(); // 函數(shù)執(zhí)行完畢,局部變量 i 占用的內(nèi)存空間被回收
console.log(i); ?// undefined
理解以上,下面開始正式理解閉包??聪旅孢@段代碼:
function a() {
? ? var i = 10;
? ? function b() {
? ? ? ? ? return i ;
? ? }
? ? return b();
}
var f = a();
console.log( f() ); // 輸出1
先看結(jié)果: 上面的代碼,我明明是在全局作用域下,卻獲取到了 局部作用域:函數(shù)a()? 中定義的變量 i。為什么?
再來回頭閱讀一遍剛剛提到的js垃圾回收: 當期嵌套的作用域鏈的其他函數(shù)的變量和參數(shù),不回收它的內(nèi)存空間?。。?/strong>
為了幫助理解:下面我們分析整段代碼在內(nèi)存中運行的過程:

第一步: 變量提升,預(yù)定義函數(shù)。
第二步: f = a();?
—> ?a() 是函數(shù),是復(fù)雜數(shù)據(jù)類型。
—> ?所以我們實質(zhì)上給f 賦的值是一串指向堆中的地址。
假設(shè):函數(shù)a堆地址為: AABBCC133。
? ? ? ?函數(shù)b堆地址為:FFFFBBBXX。
第三步:console.log(f());
—> f();?
—> 由于 f 等價于 執(zhí)行地址為:AABBCC133 的a函數(shù)。
—> 所以 f() 等價于 a()();
—> a() 的返回值,return的是 b(),而實質(zhì)上是return 了一串地址為:FFFFBBBXX 的堆地址。
—> 所以f() 實際上就是:立即執(zhí)行堆地址為
FFFFBBBXX 的函數(shù)。
注意!?。?!以下就是閉包的核心了?。。。?!
看完了全局作用域中的執(zhí)行,我們再看局部作用域:a()?
—> var i = 10;
—> 定義了一個堆地址為:FFFFBBBXX 的函數(shù)b。
—> return b();
—> 函數(shù)a執(zhí)行結(jié)束。
—> 根據(jù)js的垃圾回收機制,一個局部作用域執(zhí)行結(jié)束,就改釋放它所占用的內(nèi)存。
但是?。?!由于 函數(shù)b()預(yù)定義時,使用了函數(shù)a() 定義的變量 i 。所以此時 函數(shù)a 雖然已經(jīng)執(zhí)行完成,return了,但是其占用的內(nèi)存并沒有被釋放。
—> 接著我們在全局作用域下執(zhí)行b函數(shù)。
—> b函數(shù)執(zhí)行完成,b占用的內(nèi)存被釋放。在此時,a函數(shù)占用的內(nèi)存才被釋放。
應(yīng)該非常詳細了,如果還是不理解的話,可能需要仔細回顧js基礎(chǔ):?
1. 堆、棧的相關(guān)概念;
2. js的數(shù)據(jù)類型;
3. js的垃圾回收機制;
照著這個順序來學(xué)習(xí)回顧,然后思考為什么需要閉包,閉包在內(nèi)存中是如何實現(xiàn)的。