Function.apply不使用thisArg参数参数、Function、apply、thisArg

2023-09-08 12:12:27 作者:浅笑,整个冬天

我在写一些ActionScript3的code,尝试的方法适用于在运行时确定的对象。 AS3的文档Function.apply和Function.call双方指出的第一个参数这些功能是在执行功能时,它会被用作'这个'值的对象。

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.

但是,我已发现,在当正在执行的功能是一种方法所有的情况下,第一个参数,以应用/呼叫没有被使用,和这始终是指向其中该方法被绑定原始对象。下面是一些例子code和它的输出:

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

输出:

A
B
A
A

一个小修改上述code创建一个内嵌的匿名函数,它指的是本显示,当正在应用/调用的函数出现正确的行为是不绑定方法。

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.

我使用的应用/调用不正确,当我尝试使用它的方法?在AS3文件明确规定code对于这种情况,但是:

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.

方法功能在ActionScript不同。 方法被定义为一类确定指标的一部分,方法总是绑定到该实例。见的方法的此链接。从那里引述如下:

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:

方法是功能,这是类定义的一部分。一旦创建类的实例,一种方法是绑定到该实例。不像一类外部声明的功能,不能分开使用的方法从其所附着的实例

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中实例,它的所有方法都绑定到该实例。这就是为什么当您尝试使用通话适用,你没有看到得到覆盖。请参阅Bound方法了解详细信息。

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.

为 traits对象的解释看,本文 的,它动作用来解决方法,并用于幕后性能的原因可能是罪魁祸首。这或类方法只是语法糖以下的ECMAScript方式:

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

然后:

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!

注意 boundWork 总是会得到它所属的实例的情况下,不管你传递的执行该通话适用。其中,在ActionScript中,这种行为就是为什么类方法绑定到它们的实例。所以,无论他们在哪里时,他们仍然指向他们来自实例(这使得动作事件模型多一点理智)。一旦你理解了这一点,那么解决方法应该成为明显的。

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.

有关,你想要做一些神奇的地方,避免赞成原型功能的ActionScript 3基于硬约束的方法。

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

例如,请考虑以下ActionScript code:

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

注意的 sayName pSayName 的声明不同。 sayName 总是被绑定到它是为创建实例。 pSayName 是一个函数,可用于 MyObj中的实例,但不绑定到它的一个特例。

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.