在講閉包之前,我們先了解一下什么是自由變量。
示例代碼: let a = 1; 上述代碼中,對于函數 foo 來說,a 既不是函數參數也不是函數的局部變量的變量,因此 a 屬于自由變量。 什么是閉包在ECMAScript中,閉包(Closure)是指能夠訪問自由變量的函數。 按照以上的概念,我們可以說所有函數都是閉包,因為它們都是在創(chuàng)建的時候就保存了上層上下文的作用域鏈,觀察如下代碼: let a = 1; ECMAScript 使用的是詞法作用域(Lexical scoping,又稱靜態(tài)作用域),即在函數創(chuàng)建時,就保存上層上下文的作用域鏈,上述代碼中,foo 函數創(chuàng)建時,其所使用的變量 a 是已經在上下文中靜態(tài)保存好的,因此在執(zhí)行 foo() 時 a 的值為 1。 而任何函數,在其創(chuàng)建時保存的上層上下文的作用域中都有全局的自由變量 global(在瀏覽器中,global 為 window),因此說所有函數都是閉包。 實踐中的閉包上面說的是理論上的閉包,但在實踐中,閉包不僅僅只是能夠訪問自由變量的函數,閉包是指引用了自由變量的,并且被引用的自由變量將和這個函數一同存在的函數,在創(chuàng)建該函數的上下文已經銷毀時,該函數仍然存在。 示例代碼: function foo(){ 上述代碼中,foo 函數執(zhí)行后返回了一個匿名函數,該函數引用了自由變量 a,而在 foo() 執(zhí)行完畢后,創(chuàng)建該函數的環(huán)境已經銷毀,但該函數并沒有被銷毀,因此 foo() 的返回值就是一個閉包。 閉包會使引用的自由變量不能被清除,這就使得閉包比其他函數占用內存更多,但這也是閉包的強大之處,以下是一個使用閉包的例子: let foo = function() { 再來看一個面試中經常遇到的題目: let data = []; 這三個函數創(chuàng)建時均使用的是已經在上下文中靜態(tài)保存好的變量 i,而在 for 循環(huán)結束時,變量i 的值為3,當 我們的目標是輸出0、1、2,上面的例子顯然無法實現這個需求,利用閉包可以很輕松地解決這個問題: let data = []; |
|
來自: 昵稱10087950 > 《JAVA》