2011-08-30 51 views
9

我正在寫一些Actionscript3代碼,試圖將方法應用於在運行時確定的對象。 Function.applyFunction.call的AS3文檔都指出這些函數的第一個參數是在執行函數時將用作「this」值的對象。Function.apply不使用thisArg參數

但是,我發現在所有情況下,當被執行的函數是一個方法時,不會使用應用/調用的第一個參數,而'this'總是指該方法所綁定的原始對象。下面是一些示例代碼和其輸出:

package 
{ 
    import flash.display.Sprite;  
    public class FunctionApplyTest extends Sprite 
    { 
     public function FunctionApplyTest() 
     { 
      var objA:MyObj = new MyObj("A"); 
      var objB:MyObj = new MyObj("B"); 

      objA.sayName(); 
      objB.sayName(); 

      objA.sayName.apply(objB, []); 
      objA.sayName.call(objB); 
     } 
    } 
} 

internal class MyObj 
{ 
    private var _name:String; 
    public function MyObj(name:String) 
    { 
     _name = name; 
    } 
    public function sayName():void 
    { 
     trace(_name); 
    } 
} 

輸出:

A 
B 
A 
A 

A小調修改上面的代碼來創建一種在線匿名功能,其是指「這個」表明正確當正在應用/調用的函數不是綁定方法時,會發生行爲。

我是否在使用方法時使用apply/call不正確?在AS3文件明確規定的代碼針對這種情況,但是:

myObject.myMethod.call(myOtherObject, 1, 2, 3); 

如果這確實是壞了,有沒有變通除了使目標的方法進入功能(這將是相當難看,在我看來)?

+0

如果你需要這種編碼,我將不得不說你正在做的事情非常錯誤。你究竟想通過這樣做來完成什麼? –

+0

對我進行了測試。看起來像一個錯誤。嘗試在JIRA中搜索:http://bugs.adobe.com/jira/browse如果您沒有找到它,請將其提交 – divillysausages

+0

它不是語言錯誤,但是文檔寫得不好 –

回答

17

它不是一個「錯誤」,但callapply的文檔非常具有誤導性,並且在解釋發生了什麼事情方面做得並不好。所以這裏是對正在發生的事情的解釋。

Methods與ActionScript中的Functions不同。 Methods被定義爲類定義的一部分,並且方法總是綁定到該實例。請參閱方法第二個this link。從那裏引用:

方法是作爲類定義一部分的函數。一旦創建了類的實例,方法就會綁定到該實例。與在類外部聲明的函數不同,除了它所連接的實例外,方法不能使用。

因此,當您製作newMyObj的實例時,其所有方法都綁定到該實例。這就是爲什麼當你嘗試使用callapply時,你沒有看到this被覆蓋。詳情請參閱Bound Methods一節。

請參閱:this document有關特性對象的解釋,其中actionscript用於解決方法並用於幕後的性能原因可能是責任。這或類方法是以下的ECMAScript模式只是語法糖:

var TestClass = function(data) { 
    var self = this; 
    this.data = data; 
    this.boundWork = function() { 
     return self.constructor.prototype.unboundWork.apply(self, arguments); 
    }; 
}; 

TestClass.prototype.unboundWork = function() { 
    return this.data; 
}; 

然後:

var a = new TestClass("a"); 
var b = new TestClass("b"); 

alert(a.boundWork()); // a 
alert(b.boundWork()); // b 

alert(a.unboundWork()); // a 
alert(b.unboundWork()); // b 

alert(a.boundWork.call(b)); // a 
alert(a.boundWork.call(undefined)); // a 

alert(a.unboundWork.call(b)); // b 

或更有趣:

var method = a.unboundWork; 
method() // undefined. ACK! 

Vs的:

method = a.boundWork; 
method() // a. TADA MAGIC! 

請注意0123無論您通過thiscall還是apply傳遞,將始終在其所屬實例的上下文中執行。其中,在ActionScript中,這種行爲正是類方法綁定到其實例的原因。所以無論他們在哪裏使用,他們仍然指向他們來自的實例(這使得動作事件模型更加「理智」)。一旦你理解了這一點,那麼解決方法應該變得明顯。

對於想要做某些魔術的地方,避免使用基於ActionScript 3的硬綁定方法來支持原型函數。

例如,考慮以下ActionScript代碼:

package 
{ 
    import flash.display.Sprite;  
    public class FunctionApplyTest extends Sprite 
    { 
     public function FunctionApplyTest() 
     { 
      var objA:MyObj = new MyObj("A"); 
      var objB:MyObj = new MyObj("B"); 

      objA.sayName(); 
      objB.sayName(); 

      objA.sayName.apply(objB, []); // a 
      objA.sayName.call(objB); // a 

      objA.pSayName.call(objB) // b <--- 
     } 
    } 
} 

internal dynamic class MyObj 
{ 
    private var _name:String; 
    public function MyObj(name:String) 
    { 
     _name = name; 
    } 
    public function sayName():void 
    { 
     trace(_name); 
    } 

    prototype.pSayName = function():void { 
     trace(this._name); 
    }; 
} 

通知sayNamepSayName之間的聲明差。 sayName將始終綁定到爲其創建的實例。 pSayName是一個函數,可用於MyObj的實例,但不綁定到它的特定實例。

callapply文檔是技術上是正確的,只要你所談論的原型functions,而不是類methods,我不認爲它提到的。

+0

非常感謝您解釋這一點,這非常有啓發性!我認爲方法聲明可能不是您的第一個代碼示例的語法糖,因爲如果這是真的,那麼對於每個未綁定的方法,ClassType.prototype都會具有屬性。對我來說,這似乎是兩全其美,與Python的機制有些類似,objA.sayName()是MyObj.sayName(objA)的語法糖。 –

1

哇,這是非常令人驚訝的吳

測試它在我的身邊也並試圖在參數傳遞,以及在所有情況下,通過thisArg似乎並沒有在所有使用(明確好像給我一個錯誤)。

我不得不使用類似的東西,但有額外的約束需要訪問該方法而不創建對象的實例(這可能在其他語言但不在AS3> <)。所以我最終創建了靜態函數,並通過我自己的「thisArg」代替。

因此使得靜態函數,而不是一個可能的解決方法:

static public function SayName(thisArg : MyObj) : void 
{ 
    trace(thisArg._name); 
} 

不是最偉大的,因爲你很可能會落得像這樣加倍碼>。 <

另外,如果方法是公開的,可以改爲保存函數的函數的名稱和訪問它的方法,通過做這樣的事情:

var funcName : String = "sayName"; 
objB[funcName].apply(null, []); 
objB[funcName].call(null); 

然而,這是有限取決於範圍的方法(公共方法可以像這樣從任何地方使用,與你的類在同一個包中的內部方法和從類內部的私有方法)。所以它比使用方法的實際Function實例更具有限制性,它可以在任何地方使用。

這似乎是一個非常討厭的錯誤O.o我希望別人有更好的解決方案。

1

您是否明確嘗試過實際使用this引用,即:

internal class MyObj 
{ 
    private var _name:String; 
    public function MyObj(name:String) 
    { 
     _name = name; 
    } 
    public function sayName():void 
    { 
     trace(this._name); 
    } 
} 

這可能只是省略this關鍵字時,原始實例是用來查找的字段/變量,而什麼thisArg確實是對this關鍵字重新綁定。如果是這種情況,它最好是神祕的,但它可能值得一試。

+0

+1'thisArg' does not re-綁定'這個'。我發現'Array'文檔提供了一些[類似示例](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Array.html#filter%28%29)行爲。 – NoobsArePeople2

+0

是的,我也嘗試明確使用'this'關鍵字,不幸的是發現了相同的行爲。上面鏈接的Array.filter的文檔明確指出,如果回調函數是一個方法,'thisArg'參數必須爲null,所以過濾器的實現者似乎也遇到了這個問題。 –

相關問題