天天看點

flash AS3函數閉包代碼

閉包是可以 包含自由(未綁定)變量的代碼塊 ; 這些變量不是在這個代碼塊或者任何全局上下文中定義的,而是在定義代碼塊的環境中定義。“閉包” 一詞來源于以下兩者的結合:要執行的代碼塊(由于自由變量的存在,相關變量引用沒有釋放)和為自由變量提供綁定的

閉 包是可以包含自由(未綁定)變量的代碼塊; 這些變量不是在這個代碼塊或者任何全局上下文中定義的,而是在定義代碼塊的環境中定義。“閉包” 一詞來源于以下兩者的結合:要執行的代碼塊(由于自由變量的存在,相關變量引用沒有釋放)和為自由變量提供綁定的計算環境(作用域)。在 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  

繼續閱讀