我正在编写一些 Actionscript3 代码,试图将方法应用于在运行时确定的对象。 Function.apply 的 AS3 文档和 Function.call两者都表明这些函数的第一个参数是执行函数时将用作“this”值的对象。
但是,我发现在所有情况下,当正在执行的函数是一个方法时,应用/调用的第一个参数都没有使用,并且“this”总是指该方法绑定(bind)到的原始对象。这是一些示例代码及其输出:
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”的内联匿名函数,这表明当正在应用/调用的函数不是绑定(bind)方法时会发生正确的行为。
当我尝试在方法上使用它时,我使用的应用/调用不正确吗? AS3 文档专门为此案例提供了代码,但是:
myObject.myMethod.call(myOtherObject, 1, 2, 3);
如果这确实被破坏了,除了将目标方法变成函数之外是否还有其他解决方法(在我看来,这会很丑陋)?
最佳答案
它不是“错误”,而是 call
的文档和 apply
非常具有误导性,并且根本无法很好地解释正在发生的事情。所以这里是对正在发生的事情的解释。Methods
不同于 Functions
在 ActionScript 中。 Methods
被定义为类定义的一部分,并且方法总是绑定(bind)到该实例。参见 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.
因此,当您制作
new
MyObj
的实例,它的所有方法都绑定(bind)到该实例。这就是为什么当您尝试使用 call
或 apply
,您没有看到 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!
对比:
method = a.boundWork;
method() // a. TADA MAGIC!
请注意
boundWork
无论您为 this
传递什么,都将始终在它所属的实例的上下文中执行与 call
或 apply
.在 ActionScript 中,这种行为正是类方法绑定(bind)到它们的实例的原因。所以无论它们在哪里使用,它们仍然指向它们来自的实例(这使得 actionscript 事件模型更加“理智”)。一旦你理解了这一点,那么解决方法应该变得显而易见。对于您想要做一些魔术的地方,请避免使用基于 ActionScript 3 的硬绑定(bind)方法,而使用原型(prototype)函数。
例如,考虑以下 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
将始终绑定(bind)到为其创建的实例。 pSayName
是可用于 MyObj
的实例的函数但不绑定(bind)到它的特定实例。call
的文档和 apply
在技术上是正确的,只要你在谈论原型(prototype) functions
而不是类methods
,我认为它根本没有提到。
关于flash - Function.apply 不使用 thisArg 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7238962/