0

i have this code:

export default class Main {
  canvas: HTMLCanvasElement | null;

  context: CanvasRenderingContext2D | null;

  constructor() {
    this.canvas = null;
    this.context = null;
  }

  init() {
    this.canvas = <HTMLCanvasElement>document.getElementById('canvas');
    this.context = this.canvas.getContext('2d');

    window.requestAnimationFrame(this.gameLoop);

    return () => { };
  }

  draw() {
    const randomColor = Math.random() > 0.5 ? '#ff8080' : '#0099b0';
    this.context.fillStyle = randomColor;
    this.context.fillRect(100, 50, 200, 175);
  }

  // eslint-disable-next-line no-unused-vars
  gameLoop(timestamp: number) {
    this.draw();

    window.requestAnimationFrame(this.gameLoop);
  }

  core() {
    window.onload = this.init();
  }
}

const main = new Main();
main.core();

the error i receive is: [Error] TypeError: undefined is not an object (evaluating 'this.draw') gameLoop (main.ts:19)

but actually if I log this inside gameLoop i get undefined which makes sense because gameLoop is called innerly by requestAnimationFrame, not by my Main class. and because of the same problem, this.draw is undefined.

how to fix that?

nishi
  • 512
  • 1
  • 4
  • 19
  • 1
    You need to [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) the method to your class or use an arrow function notation. `window.requestAnimationFrame(this.gameLoop.bind(this));`. Looking for a dupe question right now – Reyno Jun 09 '21 at 15:01
  • probably there is a dupe question but i couldn't find either, so i made one myself. ill do this binding thing. Thanks. – nishi Jun 09 '21 at 15:07
  • Best I could find is ['this' is undefined in JavaScript class methods](https://stackoverflow.com/a/59060545/3257622) which has some usefull answers. Not sure if full dupe but it may point others in the right direction. – Reyno Jun 09 '21 at 15:13
  • ya, not exactly what was delighted in this question, but useful surely. But i think its better to keep this question alive tho. Could you post answer so I can apply as answer? – nishi Jun 09 '21 at 15:19
  • FYI, [there's no recursion here](https://stackoverflow.com/questions/29181253/is-requestanimationframe-implementations-recursive/66736179#66736179). – ggorlen Jun 09 '21 at 15:58

1 Answers1

1

You need to bind the method to your class to make sure this points to your class.

class Main {
  canvas;
  context;
  
  init() {
    this.canvas = document.getElementById('canvas');
    this.context = this.canvas.getContext('2d');

    window.requestAnimationFrame(this.gameLoop.bind(this));
  }

  draw() {
    const randomColor = Math.random() > 0.5 ? '#ff8080' : '#0099b0';
    this.context.fillStyle = randomColor;
    this.context.fillRect(100, 50, 200, 175);
  }
  
  gameLoop(timestamp) {
    this.draw();
    
    window.requestAnimationFrame(this.gameLoop.bind(this));
  }

  core() {
    window.onload = this.init();
  }
}

const main = new Main();
main.core();
<canvas id="canvas"></canvas>
Reyno
  • 6,119
  • 18
  • 27