Выход из области событий JavaScript - PullRequest
1 голос
/ 20 декабря 2011

Я в некотором роде новичок в области действия JavaScript, поэтому это моя проблема:

"use strict";

function Explorer(xPos, yPos) {

    // Inheritance
    GraphicsEntity.call(this, {
        x: xPos,
        y: yPos,
        width: 32,
        height: 32
    });

    // Local fields
    var _texture = new Image();

    // Contruct
    _texture.addEventListener("load", function() {

        this.graphics.drawImage(_texture, 0, 0);

    }, false);

    _texture.src = "explorer.png";

}

Это вызовет исключение: Uncaught TypeError: Невозможно вызвать метод 'drawImage' из неопределенного

Я знаю, что это связано с тем, как JavaScript работает, поскольку «this» теперь относится к полю «_texture».Как вы можете видеть, Explorer (некоторый объект, похожий на плеер) наследуется от GraphicsObject, который, в свою очередь, имеет свойство graphics (контекст элемента canvas).

Я нашел способ исправить эту проблему, нона мой взгляд, это немного грязно:

"use strict";

function Explorer(xPos, yPos) {

    // Inheritance
    GraphicsEntity.call(this, {
        x: xPos,
        y: yPos,
        width: 32,
        height: 32
    });

    // Local fields
    var _texture = new Image();
    var _graphics = this.graphics;

    // Contruct
    _texture.addEventListener("load", function() {

        _graphics.drawImage(_texture, 0, 0);

    }, false);

    _texture.src = "explorer.png";

}

Так что теперь все работает как положено, изображение аккуратно рисуется на элемент canvas.Единственная проблема заключается в том, что теперь у меня есть еще одна ссылка на «графику», которую я на самом деле не хочу.

Так что мой вопрос: есть ли способ заставить «this» ссылаться на объект Explorer или заставитьвозможности изменить?

Ответы [ 4 ]

3 голосов
/ 20 декабря 2011

this всегда локально для функции, оно оценивается каждый раз, когда вызывается функция, в зависимости от того, как вызывается функция.В этом случае браузер вызывает функцию с this, установленным для объекта изображения, на который указывает _texture.

Поскольку обычные переменные ищутся из внешней области видимости, вы можете просто сохранить старый this в некоторой переменной:

function Explorer(xPos, yPos) {
    var self = this;

    // Inheritance
    GraphicsEntity.call(this, {
        x: xPos,
        y: yPos,
        width: 32,
        height: 32
    });

    // Local fields
    var _texture = new Image();
    // Contruct

    _texture.addEventListener("load", function () {
        self.graphics.drawImage(_texture, 0, 0);
    }, false);

    _texture.src = "explorer.png";
}
2 голосов
/ 20 декабря 2011

Вы не показали функцию GraphicsEntity, но я уверен, что проблема в следующем:

GraphicsEntity.call(this, {

В вашей функции Explorer, this будет глобальным объектом (ну, если Explorer также не был вызван с call), то есть то, что вызов call устанавливает this в GraphicsEntity. Вероятно, поэтому вы получаете это исключение.

Кроме того, GraphicsEntity это объект или функция ? Я спрашиваю, потому что call ожидает функцию . call вызывает данную функцию , устанавливая первый параметр в значение this, с последующими аргументами, передаваемыми в качестве аргументов этой функции.

EDIT

Как уже сказал Esailija, значение this отличается в вашем обратном вызове события загрузки от того, что есть в начале вашей функции. Сохраните значение this в локальной переменной в начале вашей функции и используйте , что в вашем обратном вызове.

1 голос
/ 20 марта 2014

Вы также можете использовать связывание, чтобы связать контекст с областью действия функции

"использовать строгое";

функция Explorer (xPos, yPos) {

// Inheritance
GraphicsEntity.call(this, {
    x: xPos,
    y: yPos,
    width: 32,
    height: 32
});

// Local fields
var _texture = new Image();

// Contruct
_texture.addEventListener("load", function() {

    this.graphics.drawImage(_texture, 0, 0);

}.bind(this), false);

_texture.src = "explorer.png";

}

1 голос
/ 20 декабря 2011

Одним из возможных решений является использование функции-оболочки, которая создаст нужный вам контекст и захватит ваше состояние.

Как в:

function draw(me) {
    me.graphics.drawImage(_texture, 0, 0);
}

function wrapper(me) {
    return function () { draw(me) };
}

...
_texture.addEventListener('load', wrapper(this));
...

Это менее многословно, чем ваше решение? Это спорный вопрос, но вы можете сделать это достаточно общее, что он может быть повторно использован в других контекстах.

...