Это не «ошибка», но документация для call
и apply
очень вводит в заблуждение и совсем не объясняет, что происходит.Итак, вот объяснение того, что происходит.
Methods
отличаются от Functions
в ActionScript.Methods
определены как часть определения класса, и методы всегда связаны с этим экземпляром.См. Методы секунды по этой ссылке .Процитируем оттуда:
Методы - это функции, которые являются частью определения класса.Как только экземпляр класса создан, метод привязывается к этому экземпляру.В отличие от функции, объявленной вне класса, метод не может использоваться отдельно от экземпляра, к которому он присоединен.
Поэтому, когда вы создаете new
экземпляр MyObj
, все его методысвязаны с этим экземпляром.Вот почему, когда вы пытаетесь использовать call
или apply
, вы не видите, что this
переопределяется.Подробности см. В разделе Методы привязки .
См. этот документ для объяснения объекта traits , который ActionScript использует для разрешенияметоды и используемые по причинам производительности за кулисами, вероятно, виноват.Методы that или class являются просто синтаксическим сахаром для следующего шаблона 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!
Обратите внимание, что 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);
};
}
Обратите внимание на разницу в объявлении между sayName
и pSayName
.sayName
всегда будет привязан к экземпляру, для которого он был создан.pSayName
- это функция, которая доступна для экземпляров MyObj
, но не привязана к конкретному ее экземпляру.
Документация для call
и apply
технически верна, если выречь идет о прототипе functions
, а не о классе methods
, о котором я не думаю, что он вообще упоминает.