user625860
user625860

Reputation:

Prevent event inside object function to overwrite "this"

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 [object DOMWindow] has no method 'update'

Why is this happening ? "this" should relate to the Game object.

Upvotes: 2

Views: 483

Answers (4)

gion_13
gion_13

Reputation: 41533

Try this :

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

Because of the fact that setInterval and setTimeout executes your callback in the global context, your this "pointer" that you used to refer to your game object is now referring to the global object (window) , which of course has no method 'update'.

Upvotes: 0

Karl Mendes
Karl Mendes

Reputation: 649

DEMO: http://jsfiddle.net/kmendes/awzMn/

In this case there's no way you can do that because the setInterval function has a different scope. This is what you can do:

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

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

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

Upvotes: 0

Jamiec
Jamiec

Reputation: 136154

No, this in the scope of the function refers to the function itself. Its somewhat hard to wrap your head around scoping in JS if you're not used to it.

The easy solution is to cache the context of "this" outside the anonymous function and use that instead.

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

Upvotes: 0

Rob W
Rob W

Reputation: 349142

Cache the this variable, or use 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);
};

Or, using Function.bind:

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

this in a function passed to setInterval refers to the global window object, or is undefined (in strict mode).

Another method, similar to the first one. Pass this as a parameter to the function (so that no extra local variable is used):

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

Upvotes: 3

Related Questions