Actionscript 3 «этот» вопрос - PullRequest
2 голосов
/ 19 января 2011

Может ли кто-нибудь указать, почему следующий код не работает в первом случае:

CASE 1

// In a constructor
this.gallery = new Gallery();
addChild(this.gallery);

this.gallery.addEventListener(GalleryEvent.WHATEVER, function(event:*) {
    // When this callback fires, there is a fail:
    // because there is no 'this.gallery'.
    this.gallery.someAction();
});

CASE 2

this.gallery.addEventListener(GalleryEvent.WHATEVER, function(event:*) {
    // This works fine
    gallery.someAction();
})

Существуют ли правила использования this в таких случаях?

Ответы [ 2 ]

6 голосов
/ 19 января 2011

Это из-за "цепочки областей видимости".В ActionScript 3 (который совместим с ECMAScript - JavaScript работает так же, как описано ниже), имеется встроенный список «мест», который используется для разрешения любой именованной переменной, называемой цепочкой областей действия.Например, когда в «нормальном» методе класса цепочка областей действия выглядит следующим образом:

  • Текущий объект экземпляра (такой же, как this)
  • Объект класса (используется для доступа к статическим переменным)
  • Глобальная область (используется для доступа к глобальным переменным, например, Math)

Но когда вы находитесь в анонимной внутренней функции, цепочка областей действия имеет однуЕще одна запись сверху, представляющая метод, который находился в области действия в тот момент, когда анонимная функция была создана .Например, предположим, что у вас есть этот код:

class C {
    var membervar:int;

    function f() {
        var localvar:int;

        var innerfunc:Function = function() {
            // what is on the scopechain here?
        };

        innerfunc();
    }
}

В этом случае, когда вы находитесь в строке, которая говорит «что здесь находится в scopechain», scopechain выглядит следующим образом (с первой областью видимостиниже будет первое место, которое будет проверено):

  • Один экземпляр функции f(), с переменными localvar и innerfunc
  • Текущий экземпляр класса C
  • Класс C
  • Глобальная область действия

Важно понимать, что когда строка кода var innerfunc:Function = function()... выполняется, она создаетФункция объекта на лету и настройка его цепочки видимости на лету.Например, предположим, что у вас есть этот (запутанный) код, который, учитывая аргумент an_arg, возвращает функцию, которая при вызове выводит значение an_arg:

function f(an_arg:int):Function {
    return function():void {
        trace(an_arg);
    }
}

Каждая функция, возвращаемаявызовы f() имеют собственную цепочку областей видимости, указывающую на различные экземпляры f().Итак:

var func1:Function = f(3);
var func2:Function = f(4);

func1(); // prints 3
func2(); // prints 4

Распространенным способом избежать этой проблемы, если вы действительно хотите ссылаться на this во внутренней функции, а не полагаться на магию цепочки областей видимости, является создание временной переменнойвызывается self во внешней функции - в случае вашего примера кода это будет выглядеть так:

var self = this;
this.gallery.addEventListener(GalleryEvent.WHATEVER, function(event:*) {
    // This works fine
    self.gallery.someAction();
})

Я мог бы продолжать эту тему вечно - я нахожу это захватывающим :-)

4 голосов
/ 19 января 2011

потому что вы передаете эту функцию function(event:*), что означает, что она выполняется в этой области.

, поэтому, когда она пытается найти this, она ищет event.gallery.someAction();

когда вы используете gallery, он пытается найти его в списке глобальных переменных.

Один из способов проверить это - добавить трассировку (это) и посмотреть, что произойдет.

...