閉包:是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)。
創(chuàng)建閉包的常見方式,是在一個函數(shù)內(nèi)部創(chuàng)建另外一個函數(shù):

如上,看Fn函數(shù)return出來的內(nèi)部函數(shù)(匿名函數(shù))中的前兩行代碼,這個兩行代碼訪問了外部函數(shù)中的變量propertyname,即使該函數(shù)被返回,而且在其他地方調(diào)用了,但是他任然可以訪問propertyname這個變量。(一句話理解閉包:JavaScript中的函數(shù)運行在它們被定義的作用域里,而不是它們被執(zhí)行的作用域里)。這是因為在內(nèi)部函數(shù)的作用域鏈中包含了外部函數(shù)Fn的作用域。
了解閉包之前,讓我們了解下如何創(chuàng)建作用域鏈以及作用域鏈的作用是什么?
首先,當某個函數(shù)被調(diào)用的時候,會創(chuàng)建一個執(zhí)行環(huán)境以及相應(yīng)的作用域鏈,然后使用arguments和其他命名參數(shù)的值初始化函數(shù)的活動對象。在函數(shù)執(zhí)行的過程中,就需要在作用域鏈中查找變量。如下舉個栗子:

如上代碼,首先是定義了一個Fn函數(shù),然后在全局中調(diào)用了它,執(zhí)行Fn()的時候,會創(chuàng)建一個包含arguments,val1,val2的活動對象,全局執(zhí)行環(huán)境的變量對象包含有res,F(xiàn)n。那么全局執(zhí)行環(huán)境的作用域則是處于Fn執(zhí)行環(huán)境的作用域鏈的第二位。
在后臺的每個執(zhí)行環(huán)境都有一個表示變量的對象--變量對象。全局環(huán)境中的變量對象是始終存在的,然后像Fn函數(shù)這樣局部環(huán)境的變量對象,只有在函數(shù)執(zhí)行的過程中存在。在創(chuàng)建Fn函數(shù)的時候會預(yù)先創(chuàng)建一個包含全局變量對象的作用域鏈。這個作用域鏈保存在內(nèi)部的[[Scope]]屬性中。在調(diào)用Fn函數(shù)的時候,會創(chuàng)建一個執(zhí)行環(huán)境,然后通過復制函數(shù)的[[Scope]]屬性中的對象構(gòu)建起執(zhí)行環(huán)境的作用域鏈,此后,又有一個活動對象(在此作為變量對象使用)被創(chuàng)建并推入執(zhí)行環(huán)境作用域鏈的前端。
以上有三關(guān)鍵詞:執(zhí)行環(huán)境,變量對象,活動對象。注意理清楚他們之間的關(guān)系。
一般情況下,當函數(shù)執(zhí)行完畢后,局部活動對象就會被銷毀,內(nèi)存中只會保存全局執(zhí)行環(huán)境的變量對象。但是閉包卻不是這樣。舉個栗子:

以上函數(shù)Wrapper中的匿名函數(shù)會將外部函數(shù)的活動對象添加到他的作用域鏈中,即返回出的匿名函數(shù)的作用域鏈被初始化為包含Wrapper函數(shù)的活動對象和全局的活動對象。這樣Wrapper()函數(shù)執(zhí)行完成后,其活動對象不會被銷毀,因為匿名函數(shù)的作用域鏈任然存在,而且引用著外部函數(shù)的活動對象,直到匿名函數(shù)被銷毀后,外面的函數(shù)的活動對象才會全部銷毀。
--------以上根據(jù)javascript高級程序設(shè)計總結(jié)。我弄明白了,你呢?