閉包是有權訪問另外一個函數作用域中變量的函數
在了解閉包之前,需要先了解幾個概念,具體如下:
當某個環(huán)境被調用的時候,會創(chuàng)建一個執(zhí)行環(huán)境以及相應的作用域鏈。然后,使用arguments和其他命名參數的值來初始化函數的活動對象。但在作用域鏈中,外部函數的活動對象始終在第二位,外部函數的外部函數,排在了第三位,以此類推,排外最尾部的是全局執(zhí)行環(huán)境。
執(zhí)行環(huán)境
執(zhí)行環(huán)境(execution context)又稱為執(zhí)行上下文,有時直接稱之為環(huán)境,是JavaScript中一個很重要的概念。通過它可以判斷變量或者函數是否有權訪問其他數據。每個執(zhí)行環(huán)境都有一個變量對象(variable object),這個對象中包含了在這個環(huán)境中定義的所有的變量和函數。全局執(zhí)行環(huán)境是最底層的執(zhí)行環(huán)境。在web瀏覽器中,全局執(zhí)行環(huán)境被認為是window對象,因此所有的全局變量和函數都是作為window對象的屬性和方法創(chuàng)建的。當某個執(zhí)行環(huán)境里面的代碼全部執(zhí)行完畢的時候,該環(huán)境就會被銷毀,包括該環(huán)境中的所有變量,定義的函數也會隨之銷毀。而全局執(zhí)行環(huán)境是一直到關閉瀏覽器才會被銷毀。
每個函數都有自己的執(zhí)行環(huán)境,當執(zhí)行流進入這個函數的時候,函數的環(huán)境就會被推入一個環(huán)境棧中,當函數執(zhí)行完畢后,棧將其環(huán)境彈出。
作用域鏈
當代碼在環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈。作用域鏈的作用是保證對執(zhí)行環(huán)境有權訪問的所有變量和函數的有序訪問。他的本質上是一個指向變量對象的指針列表。其第一個節(jié)點里有當前環(huán)境的變量對象(如果環(huán)境是函數,這把活動對象(一開始為arguments)作為變量對象)。第二個節(jié)點為其環(huán)境的下一個包含環(huán)境的變量對象以此類推,一直到全局執(zhí)行環(huán)境包含的變量對象(全局環(huán)境沒有arguments)。
尋找某一個變量或者函數時,都是沿著作用域鏈開始層層往后搜索,一直到找到為止,如果找不到,則返回undefined。
閉包
閉包的概念其實并不復雜,就是有權訪問另外一個函數作用域中變量的函數。通常的創(chuàng)建方式為一個函數內部創(chuàng)建另一個函數。
當然,還有一種更廣泛的理解,只要是內部函數以值傳遞的形式,或者當做參數,傳遞給外部函數,那么就發(fā)生了閉包
PS
1.閉包中內部函數取得外部函數的變量永遠是最后一個值。
2.閉包中,內部函數永遠無法取到外部函數的this和arguments,只能取到活動對象。