flash – Function.apply不使用thisArg参数

前端之家收集整理的这篇文章主要介绍了flash – Function.apply不使用thisArg参数前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在编写一些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);
    }
}

输出

A
B
A
A

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

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

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

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

解决方法

它不是一个“bug”,但是调用和应用的文档非常具有误导性,并且在解释最新情况时并没有做得很好.所以这里是对正在发生的事情的解释.

方法与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实例的函数,但未绑定到它的特定实例.

调用和应用的文档在技术上是正确的,只要你谈论的是原型函数而不是类方法,我认为它根本没有提及.

猜你在找的Flash相关文章