2011-01-19 92 views
2

有人能指出爲什麼下面的代碼在第一種情況下會失敗:ActionScript 3的 '本' 的問題

CASE 1

// In a constructor 
this.gallery = new Gallery(); 
addChild(this.gallery); 

this.gallery.addEventListener(GalleryEvent.WHATEVER, function(event:*) { 
    // When this callback fires, there is a fail: 
    // because there is no 'this.gallery'. 
    this.gallery.someAction(); 
}); 

CASE 2

this.gallery.addEventListener(GalleryEvent.WHATEVER, function(event:*) { 
    // This works fine 
    gallery.someAction(); 
}) 

在這種情況下是否有關於this使用的規則?

+1

嘗試添加監聽* *沒有**使用匿名功能。 – 2011-01-19 00:49:28

回答

6

這是因爲「範圍鏈」。在ActionScript 3中(與ECMAScript兼容 - JavaScript具有下述相同的行爲),有一個內置的「位置」列表,用於解析任何命名變量,稱爲作用域鏈。例如。當在一個類的一個「正常」的方法,該作用域鏈看起來像這樣:

  • 當前實例對象(同this
  • 類對象(用於訪問靜態變量)
  • 全局範圍(用於訪問全局變量,例如Math

但是,當你在一個匿名內部功能,範圍鏈具有在頂部一個條目,表示在範圍上在該點的方法匿名功能的時間離子是創建的。因此,例如,假設你有這樣的代碼:

class C { 
    var membervar:int; 

    function f() { 
     var localvar:int; 

     var innerfunc:Function = function() { 
      // what is on the scopechain here? 
     }; 

     innerfunc(); 
    } 
} 

在這種情況下,當你的,說:「什麼是對的scopechain這裏」時,scopechain看起來像這樣(下面是第一個範圍的行將要檢查第1名):功能f()

  • 一個實例,用變量localvarinnerfunc
  • 類的當前實例C
  • ŧ他類C
  • 全球範圍

認識到這一點很重要,當代碼var innerfunc:Function = function()...執行行,它是動態創建的功能對象,和設置在飛行中的作用域鏈。因此,例如,假設你有這個(混亂)的代碼,其中,有一個參數an_arg,返回該函數被調用時,將打印an_arg的價值:

function f(an_arg:int):Function { 
    return function():void { 
     trace(an_arg); 
    } 
} 

通過調用返回到f()每個功能都有它自己的作用域鏈,指向f()的不同實例。所以:

var func1:Function = f(3); 
var func2:Function = f(4); 

func1(); // prints 3 
func2(); // prints 4 

常見的方式,以避免這個問題,如果你真的想引用this在內部函數,而不是依賴於作用域鏈的法寶,是建立在所謂的self一個臨時變量外功能 - 在你的示例代碼的情況下,它應該是這樣的:

var self = this; 
this.gallery.addEventListener(GalleryEvent.WHATEVER, function(event:*) { 
    // This works fine 
    self.gallery.someAction(); 
}) 

我能在這個問題上永遠持續下去 - 我覺得很有意思:-)

4

因爲你傳遞了這個函數function(event:*)這意味着它在該範圍內執行。

所以當它試圖尋找this它正在尋找event.gallery.someAction();

當您使用gallery,它試圖全局變量的列表中找到它。

驗證此方法的一種方法是添加跟蹤(此)並查看會發生什麼。