0

A class is defined as follow:

export default class FishGame {
  constructor(window) {
    .......
    this.window = window
    ......
  }

  gameloop() {
    this.window.requestAnimationFrame(this.gameloop);
    var now = Date.now();
    this.deltaTime = now - this.lastTime;
    this.lastTime = now;
    ....
  }
}

you can see the function gameloop is a recursive call. I call this function in this way:

 function game() {
    let fishGame = new FishGame(this);
    fishGame.gameloop();
 }

while a exception is thrown, could someone tell me why this object is null?: enter image description here

Cœur
  • 37,241
  • 25
  • 195
  • 267
truejasonxiefans
  • 179
  • 2
  • 12
  • [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) isn't recursive. – ggorlen Aug 12 '18 at 04:17
  • Change to this: `this.window.requestAnimationFrame(this.gameloop.bind(this));`. Passing a method to a function as a callback loses the `this` that you want to go with it so you can use `.bind()` to force it to be attached properly. – jfriend00 Aug 12 '18 at 04:47

2 Answers2

1

The problem is that this is lost in the callback. There are a few clean ways of doing it described in this post. One approach is to bind this to the callback, or use an arrow function which has this bound to it automatically:

class FishGame {
  constructor() {}

  gameloop() {
    requestAnimationFrame(() => this.gameloop());
    console.log(Date.now());
  }
}

new FishGame().gameloop();
ggorlen
  • 44,755
  • 7
  • 76
  • 106
  • Hi ggorlen, I can't make it work by use "self". Is there any difference with "this"? – truejasonxiefans Aug 12 '18 at 04:35
  • Yeah, the difference is that `this` gets lost inside the `requestAnimationFrame` context. It stops pointing to an instance of `FishGame`. What do you mean you can't make it work--can you be more specific? The code snippet works fine for me. – ggorlen Aug 12 '18 at 04:36
  • Hi ggorlen, it does work! thanks a a lot. While I want to know why this gets lost in requestAnimationFrame? can we use the bind mechanism? – truejasonxiefans Aug 12 '18 at 04:44
  • You can--there should be all the info you need in [this post](https://stackoverflow.com/questions/6065169/requestanimationframe-with-this-keyword). – ggorlen Aug 12 '18 at 05:09
  • 1
    There are much better ways to solve this than using a global variable. – Felix Kling Aug 12 '18 at 05:30
  • @FelixKling agreed completely. I wanted to use a similar technique as the OP but I've updated to use best practice. – ggorlen Aug 12 '18 at 16:51
0

class FishGame {
  static loop(game) {
    function doloop() {
      requestAnimationFrame(doloop)
      game.gameloop()
    }
    
    doloop()
  }
  
  constructor() {
    self = this;
    this.name = "Lamax"
  }

  gameloop() {
    console.log(Date.now()+": "+this.name);
  }
}

FishGame.loop(new FishGame());

The problem is that you are calling this, inside the function thats passed as a argument in requestAnimationFrame, try the above snipet

andylamax
  • 1,858
  • 1
  • 14
  • 31
  • 1
    although I add this, it would thrown null in the second call of gameloop. you can see it was successfully log the window object in first time. – truejasonxiefans Aug 12 '18 at 04:31