但是,我发现在所有情况下,当正在执行的函数是一个方法时,不使用apply / call的第一个参数,’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
对上述代码的一个小修改,以创建一个引用’this’的内联匿名函数,表明当被应用/调用的函数不是绑定方法时,会发生正确的行为.
当我尝试在方法上使用它时,我是否使用了apply / call错误? AS3文档专门为此案例提供了代码,但是:
myObject.myMethod.call(myOtherObject,1,2,3);
解决方法
方法与ActionScript中的函数不同.方法被定义为类定义的一部分,方法总是绑定到该实例.参见this link的方法.从那里引用:
Methods are functions that are part of a class definition. Once an instance of the class is created,a method is bound to that instance. Unlike a function declared outside a class,a method cannot be used apart from the instance to which it is attached.
因此,当您创建MyObj的新实例时,其所有方法都绑定到该实例.这就是为什么当你尝试使用call或apply时,你没有看到这被覆盖.有关详细信息,请参阅Bound Methods部分.
有关traits对象的解释,请参阅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!
请注意,无论您使用call或apply传入什么内容,boundWork都将始终在其所属实例的上下文中执行.在ActionScript中,这种行为正是将类方法绑定到其实例的原因.因此,无论它们在何处使用,它们仍然指向它们来自的实例(这使得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); }; }
注意sayName和pSayName之间的声明差异. sayName将始终绑定到为其创建的实例. pSayName是一个可用于MyObj实例的函数,但未绑定到它的特定实例.