Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nested function cant find itself in Typescript

I have the following code:

//Main Entry Point.
start() {
    this.init();
    this.gameLoop();
}

//Init, runs only once.
init() {
    let initalEntity1: Entity = new Entity(10, 10, Gender.female);
    let initalEntity2: Entity = new Entity(60, 60, Gender.male);
    console.log("There are " + this.Entities.length + " Items in the entities Array")
    this.Entities.push(initalEntity1, initalEntity2);
    console.log("There are " + this.Entities.length + " Items in the entities Array")
}

gameLoop() {
    console.log("Performing a Game Loop");
    requestAnimationFrame(this.gameLoop);

    //MAIN LOOP THROUGH ENTITIES
    for (let i in this.Entities) {
            this.Render.drawEntitysToScreen(this.Entities[i].EntityPosition, this.Entities[i].gender);
        }
}

It enters into start() fine, and also performs all of the init() functionality. it them proceeds onto gameloop() which it will run once, however the line requestAnimationFrame(this.gameLoop); which is ment to retrigger the function to be called as a Canvas frame is causing the following error:

TypeError: this is undefined

trying to requestAnimationFrame(gameLoop); but it causes the typescript compiler to get upset...

like image 414
tornup Avatar asked Feb 21 '26 19:02

tornup


1 Answers

This is due to how this binding works in javascript. The way by which you are passing this.gameLoop to requestAnimationFrame is essentially passing an unbound gameLoop function, and so when it is called, it has lost reference to its this.

There are a number of possible solutions to this problem:

  1. You can bind this.gameLoop to this inside of the class constructor, like so:

    constructor() {
      this.gameLoop = this.gameLoop.bind(this);
    }
    
  2. You can bind this.gameLoop to this as part of the gameLoop method definition. Rather than defining gameLoop like

    gameLoop() {
    

    If you instead use

    gameLoop = () => {
    

    it will be automatically bound to this. This is a property of using the fat arrow for function declarations: it automatically performs binding to the this that exists at the function declaration.

  3. You can change how you pass gameLoop to requestAnimationFrame:

    requestAnimationFrame(() => this.gameLoop());
    

    This again takes advantage of the automatic this binding performed by the arrow function, but instead of doing it as part of the class method declaration you can simply do it lazily at the time you need it to be bound.

    Note, however, that doing it this way does mean that a new function will be created each time gameLoop is called.

like image 135
casieber Avatar answered Feb 23 '26 08:02

casieber



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!