閉包是可以 包含自由(未綁定)變量的代碼塊 ; 這些變量不是在這個代碼塊或者任何全局上下文中定義的,而是在定義代碼塊的環境中定義。“閉包” 一詞來源于以下兩者的結合:要執行的代碼塊(由于自由變量的存在,相關變量引用沒有釋放)和為自由變量提供綁定的
閉 包是可以包含自由(未綁定)變量的代碼塊; 這些變量不是在這個代碼塊或者任何全局上下文中定義的,而是在定義代碼塊的環境中定義。“閉包” 一詞來源于以下兩者的結合:要執行的代碼塊(由于自由變量的存在,相關變量引用沒有釋放)和為自由變量提供綁定的計算環境(作用域)。在 Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby 和 Python 等語言中都能找到對閉包不同程度的支援。
閉包的價值在于可以作為函數對象 或者匿名函數,對于類型系統而言這就意味着不僅要表示資料還要表示代碼。支援閉包的多數語言都将函數作為第一級對象,就是說這些 函數可以存儲到變量中、作為參數傳遞給其他函數,最重要的是能夠被函數動态地建立和傳回 。
package
{
import flash.display.Sprite;
public class Test extends Sprite
{
private var array:Array = new Array();
public function Test()
{
for (var i:int = 0; i < 5; i++) {
var object:Object = new Object();
object.num = function():void {
this.number = i;
trace(this.number);
}
array.push(object);
} }
public function run():void {
for (var i:int = 0; i < array.length; i++) {
array.num();
}
}
}
} package
{
import flash.display.Sprite;
public class RunTest extends Sprite
{
public function RunTest()
{
var t:Test = new Test();
t.run();
}
}
}
先調用 setup 方法,在 setup 方法的 for 語句中循環建立對象 obj,并為 obj 建立一個方法 num(),該方法将目前循環的 index 指派給 obj 的一個屬性 n,并 trace 出 n 的值。将 for 循環生成的對象存到數組 array 中用于在 run 方法中取出。 調用 run 方法,取出 array 中的對象,并調用他們的 num() 方法。 猜猜輸出的結果是什麼? 結果是: 5 5 5 5 5 并不是期望中的(我期望中的): 0 1 2 3 4 為什麼呢? 研究并實驗了幾下才發現,原來 函數閉包雖然可以記錄上下文環境的 snapshot ,但卻是最近狀态的一個 snapshot ,比如上例在 for 循環中,雖然把循環的目前的 i 值賦給了 n ,然而 i 是屬于 num() 函數之外的,是 snapshot 中的變量,是以它隻記錄最近的狀态,也就是 for 循環的最後一次,i 等于 5 。輸出的就都是 5 了。按照這個原理,你也可以實驗一下,把 i 的最後狀态改成其他的值,比如 public function setup():void
{
for(var i:int=0;i<5;i++)
{
var obj:Object = {}
obj.num = function():void
{
this.n = i
trace(this.n)
}
array.push(obj)
}
i = 100
} 雖然在 for 循環結束之後才設定的值,不過 i 依然在那個 snapshot 的範圍之内,是以輸出将會是 5 個 100 。 既然知道了原理,問題解決起來就容易了。隻要讓 i 不在函數閉包的上下文環境的 snapshot 的範圍裡就好了。可以這樣改寫一下:
public var array:Array = []
public function setup():void{
for(var i:int=0;i<5;i++)
{
array.push(createObj(i))
}
}
public function run():void
{
for(var j:int=0;j<5;j++)
{
array[j].num()
}
}
public function createObj(index:int):Object
{
var obj:Object = {}
obj.num = function():void
{
this.n = index
trace(this.n)
}
return obj
} 将建立函數閉包的部分拿到 createObj() 方法中,這樣這個 snapshot 隻是該函數的上下文環境,不會受到 i 的重複指派的影響,輸出結果也是預期的 0 1 2 3 4