本文介绍了Function.apply 不使用 thisArg 参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一些 Actionscript3 代码,尝试将方法应用于在运行时确定的对象.Function.apply 的 AS3 文档href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Function.html#call%28%29">Function.call 都表示这些函数的第一个参数是在执行函数时将用作this"值的对象.

但是,我发现在所有情况下,当执行的函数是方法时,不使用 apply/call 的第一个参数,并且this"始终指的是绑定该方法的原始对象.下面是一些示例代码及其输出:

包{导入 flash.display.Sprite;公共类 FunctionApplyTest 扩展了 Sprite{公共函数 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);}}}内部类 MyObj{私有变量_name:字符串;公共函数 MyObj(name:String){_name = 名称;}公共函数 sayName():void{跟踪(_名称);}}

输出:

A乙一种一种

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

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

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

如果这确实坏了,除了将目标方法变成函数(在我看来这会很丑陋)之外,还有其他解决方法吗?

解决方案

它不是错误",但是 callapply 的文档非常具有误导性,并且没有根本无法解释正在发生的事情.所以这里是对正在发生的事情的解释.

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

方法是作为类定义一部分的函数.一旦创建了类的实例,就会将一个方法绑定到该实例.与在类外声明的函数不同,方法不能与它所附加的实例分开使用.

因此,当您创建 MyObjnew 实例时,其所有方法都绑定到该实例.这就是为什么当您尝试使用 callapply 时,您不会看到 this 被覆盖.有关详细信息,请参阅fbf351e63e3d1020a9b>fa9b7b部分.

请参阅本文档,了解特征对象,可能是因为动作脚本用于解析方法并用于幕后的性能原因.那个或类方法只是以下 ECMAScript 模式的语法糖:

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

那么:

var a = new TestClass("a");var b = new TestClass("b");警报(a.boundWork());//一种警报(b.boundWork());//乙警报(a.unboundWork());//一种警报(b.unboundWork());//乙警报(a.boundWork.call(b));//一种警报(a.boundWork.call(未定义));//一种警报(a.unboundWork.call(b));//乙

甚至更有趣:

var method = a.unboundWork;method()//未定义.确认!

对比:

method = a.boundWork;方法()//a.多田魔术!

请注意,boundWork 将始终在其所属实例的上下文中执行,无论您使用 callthis 传入什么> 或 申请.在 ActionScript 中,这种行为正是类方法绑定到它们的实例的原因.因此,无论在哪里使用它们,它们仍然指向它们来自的实例(这使得 actionscript 事件模型更加理智").一旦你理解了这一点,那么解决方法就很明显了.

对于您想要施展魔法的地方,请避免使用基于 ActionScript 3 的硬绑定方法,而使用原型函数.

例如,考虑以下 ActionScript 代码:

包{导入 flash.display.Sprite;公共类 FunctionApplyTest 扩展了 Sprite{公共函数 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);//一种objA.pSayName.call(objB)//b <---}}}内部动态类 MyObj{私有变量_name:字符串;公共函数 MyObj(name:String){_name = 名称;}公共函数 sayName():void{跟踪(_名称);}原型.pSayName = function():void {跟踪(this._name);};}

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

callapply 的文档在技术上是正确的,只要您谈论的是原型 functions 而不是 class methods,我认为它根本没有提到.

I'm writing some Actionscript3 code that attempts to apply a method to an object that is determined at runtime. The AS3 documentation for Function.apply and Function.call both indicate that the first argument to those functions is the object which will be used as the 'this' value when the function is executed.

However, I have found that in all cases when the function being executed is a method, the first parameter to apply/call is not used, and 'this' always refers to the original object to which that method was bound. Here is some example code and its output:

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);
    }
}

Output:

A
B
A
A

A minor modification to the above code to create an in-line anonymous function which refers to 'this' shows that the correct behavior occurs when the function being applied/called is not a bound method.

Am I using apply/call incorrect when I attempt to use it on a method? The AS3 documentation specifically provides code for this case, however:

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

If this is indeed broken, is there any work-around besides making the target methods into functions (which would be quite ugly, in my opinion)?

解决方案

Its not a "bug", but the documentation for call and apply is very misleading and doesn't do a good job at all of explaining whats going on. So here is an explaination of what is happening.

Methods are different from Functions in ActionScript. Methods are defined as a part of a class defintion, and methods are always bound to that instance. See the Methods second of this link. To quote from there:

So when you make a new instance of MyObj, all of its methods are bound to that instance. Which is why when you try to use call or apply, you aren't seeing this getting overridden. See the section on Bound Methods for details.

See, this document for an explanation of the traits object, which actionscript uses to resolve methods and used for performance reasons behind the scenes is probably to blame. That or class methods are just syntactic sugar for the following ECMAScript pattern:

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;
};

Then:

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

or even more interesting:

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

Vs:

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

Notice that boundWork will always get executed in the context of the instance it belongs to, no matter what you pass in for this with call or apply. Which, in ActionScript, this behavior is exactly why class methods are bound to their instance. So no matter where they are used, they still point at the instance they came from (which makes the actionscript event model a little more "sane"). Once you understand this, then a work-around should become obvious.

For places where you want to do some magic, avoid the ActionScript 3 based hard-bound methods in favor of prototype functions.

For example, consider the following ActionScript code:

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);
    };
}

Notice the declaration difference between sayName and pSayName. sayName will always be bound to the instance it was created for. pSayName is a function that is available to instances of MyObj but is not bound to a particular instance of it.

The documentation for call and apply are technically correct, as long as you are talking about prototypical functions and not class methods, which I don't think it mentions at all.

这篇关于Function.apply 不使用 thisArg 参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 17:25