Предотвратить событие внутри функции объекта, чтобы перезаписать «это» - PullRequest
2 голосов
/ 18 января 2012
Game.prototype.run = function() {
    window.setInterval(function() {
        var thisLoop = new Date().getTime();

        this.update();
        this.render();

        lastLoop = thisLoop;
    }, 1000 / this.fps);
};

game.js: 198Uncaught TypeError: Object [объект DOMWindow] не имеет метода 'update'

Почему это происходит? «this» должно относиться к объекту Game.

Ответы [ 4 ]

3 голосов
/ 18 января 2012

Кэшируйте переменную this или используйте Function.bind:

Game.prototype.run = function() {
    var _this = this;
    window.setInterval(function() {
        var thisLoop = new Date().getTime();
        _this.update();
        _this.render();
        lastLoop = thisLoop;
    }, 1000 / this.fps);
};

Или используйте Function.bind:

Game.prototype.run = function() {
    window.setInterval((function() {
        ... 
    }.bind(this), 1000 / this.fps);
};

this в функции, переданной в setInterval, относится к глобальному объекту window или undefined (в строгом режиме).

Другой метод, аналогичный первому.Передайте this в качестве параметра функции (чтобы не использовать дополнительную локальную переменную):

Game.prototype.run = function() {
    window.setInterval(function(_this) {
        var thisLoop = new Date().getTime();
        _this.update();
        _this.render();
        lastLoop = thisLoop;
    }, 1000 / this.fps, this);
};
0 голосов
/ 18 января 2012

ДЕМО: http://jsfiddle.net/kmendes/awzMn/

В этом случае вы не можете это сделать, потому что функция setInterval имеет другую область видимости. Вот что вы можете сделать:

Game.prototype.run = function() {
    var currentGame = this;
    window.setInterval(function() {
        var thisLoop = new Date().getTime();

        currentGame.update();
        currentGame.render();

        lastLoop = thisLoop;
    }, 1000 / this.fps);
};
0 голосов
/ 18 января 2012

Нет, это в объеме функции относится к самой функции.В JS довольно сложно обернуть голову в область видимости, если вы к ней не привыкли.

Простое решение - кэшировать контекст «this» вне анонимной функции и использовать его вместо этого.

Game.prototype.run = function() {
  var game = this;
  window.setInterval(function() {
    var thisLoop = new Date().getTime();
    game.update();
    game.render();
    lastLoop = thisLoop;
  }, 1000 / this.fps);
};
0 голосов
/ 18 января 2012

Попробуйте:

Game.prototype.run = function() {
    var intervalCallBack = function() {
        var thisLoop = new Date().getTime();
        this.update();
        this.render();
        lastLoop = thisLoop;
    };
    var self = this;
    window.setInterval(function(){intervalCallBack.call(self);}, 1000 / this.fps);
};

Из-за того, что setInterval и setTimeout выполняют ваш обратный вызов в глобальном контексте, ваш this «указатель», который вы использовали для ссылки на вашу игруобъект теперь ссылается на глобальный объект (window), который, конечно, не имеет метода 'update' .

...