Function.apply不使用thisArg参数

Cha*_*lis 9 apache-flex flash functional-programming actionscript-3

我正在编写一些Actionscript3代码,试图将方法应用于在运行时确定的对象.Function.applyFunction.call的AS3文档都指出这些函数的第一个参数是在执行函数时将用作'this'值的对象.

但是,我发现在所有情况下,当正在执行的函数是一个方法时,不使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

A
B
A
A
Run Code Online (Sandbox Code Playgroud)

对上述代码的一个小修改,以创建一个引用'this'的内联匿名函数,表明当被应用/调用的函数不是绑定方法时,会发生正确的行为.

当我尝试在方法上使用时,我是否使用了apply/call错误?AS3文档专门为此案例提供了代码,但是:

myObject.myMethod.call(myOtherObject, 1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

如果这确实被打破了,除了将目标方法变成函数之外还有其他解决方法(在我看来这会非常难看)吗?

J. *_*mes 17

它不是一个"错误",但是文档callapply非常误导,并没有很好地解释发生了什么.所以这里是对正在发生的事情的解释.

MethodsFunctionsActionScript 不同.Methods被定义为类定义的一部分,方法总是绑定到该实例.请参阅此链接方法第二部分.从那里引用:

方法是属于类定义的函数.创建类的实例后,方法将绑定到该实例.与在类外声明的函数不同,方法不能与它所附加的实例分开使用.

因此,当您创建new实例时MyObj,其所有方法都绑定到该实例.这就是为什么当你尝试使用call或者apply,你没有看到this被覆盖的原因.有关详细信息,请参阅绑定方法部分.

请参阅此文档以获取traits对象的解释,其中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;
};
Run Code Online (Sandbox Code Playgroud)

然后:

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
Run Code Online (Sandbox Code Playgroud)

甚至更有趣:

var method = a.unboundWork;
method() // undefined. ACK!
Run Code Online (Sandbox Code Playgroud)

VS:

method = a.boundWork;
method() // a. TADA MAGIC!
Run Code Online (Sandbox Code Playgroud)

请注意,boundWork无论您this使用call或传入的是什么,它总是会在它所属的实例的上下文中执行apply.在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);
    };
}
Run Code Online (Sandbox Code Playgroud)

注意sayName和之间的声明差异pSayName.sayName将始终绑定到为其创建的实例.pSayName是一个可用于实例的函数,MyObj但不绑定到它的特定实例.

只要你谈论的是原型而不是阶级的文档,call并且apply在技​​术上是正确的,我认为它根本没有提及.functionsmethods