先從閉包特點(diǎn)解釋,應(yīng)該更好理解.
閉包的兩個特點(diǎn):
1、作為一個函數(shù)變量的一個引用 - 當(dāng)函數(shù)返回時,其處于激活狀態(tài)。 2、一個閉包就是當(dāng)一個函數(shù)返回時,一個沒有釋放資源的棧區(qū)。
其實(shí)上面兩點(diǎn)可以合成一點(diǎn),就是閉包函數(shù)返回時,該函數(shù)內(nèi)部變量處于激活狀態(tài),函數(shù)所在棧區(qū)依然保留.
我們所熟知的主流語言,像C,java等,在函數(shù)內(nèi)部只要執(zhí)行了return,函數(shù)就會返回結(jié)果,然后內(nèi)存中刪除該函數(shù)所在的區(qū)域.生命周期也就停止了.一般的js函數(shù)也是這樣. 但是有閉包特性的js函數(shù)有點(diǎn)特殊. 就例子來說: function a(){ var i=0; function b(){ alert(++i); } return b; } var c = a(); c();
這是個標(biāo)準(zhǔn)的閉包.在函數(shù)a中定義了函數(shù)b,a又return了b的值.這些可以先不管. var c = a(); c(); 這兩句執(zhí)行很重要. 在var c = a();這行里,執(zhí)行了a函數(shù),那么肯定a經(jīng)過了return.按照主流語言的函數(shù)特性,現(xiàn)在c的值就是a的返回值. 第二行c()的執(zhí)行實(shí)際執(zhí)行的就是b函數(shù).最后不管執(zhí)行的是誰,會彈出一個值為0的窗口,到此為止,所有的生命周期按理論來說就算全部結(jié)束了. 可是,如果我們再多執(zhí)行一行. var c = a(); c(); c(); 第一次彈出0,第二次執(zhí)行卻彈出了1.
也就是說,第一次c()后,a中的i依然保留.自然a在內(nèi)存的棧區(qū)依然保留.
a是return過了,但是,a及內(nèi)部值卻依然存在,這就是閉包.
好了,總結(jié)下, 1,閉包外層是個函數(shù). 2,閉包內(nèi)部都有函數(shù). 3,閉包會return內(nèi)部函數(shù). 4,閉包返回的函數(shù)內(nèi)部不能有return.(因?yàn)檫@樣就真的結(jié)束了) 5,執(zhí)行閉包后,閉包內(nèi)部變量會存在,而閉包內(nèi)部函數(shù)的內(nèi)部變量不會存在.
閉包的應(yīng)用場景(呵呵,復(fù)制的參考資料) 1、保護(hù)函數(shù)內(nèi)的變量安全。以最開始的例子為例,函數(shù)a中i只有函數(shù)b才能訪問,而無法通過其他途徑訪問到,因此保護(hù)了i的安全性。 2、在內(nèi)存中維持一個變量。依然如前例,由于閉包,函數(shù)a中i的一直存在于內(nèi)存中,因此每次執(zhí)行c(),都會給i自加1。
根據(jù)參考資料的應(yīng)用場景,我們會自然的想到j(luò)ava或是c++的類.雖然JS沒有類的概念,但是有了類的相似執(zhí)行結(jié)果.
另外,還有一種格式頗受爭議: (function(a,b){...})(a,b); 如果你使用過jquery,并且觀察過他的代碼,你就會很奇怪他的寫法,網(wǎng)上有人也把這種格式叫做閉包.
|