1

I keep running into bizarre problems. I've been unable to find anything on them after doing some research, so I thought I'd come here to present them. I have a class which is rather long, but I'll include the relevant bits:

class AnimatedSnake {

constructor(canvasId, coordinates) {

    this.coordinates = coordinates;
    this.direction = 2;

    this.ctx = document.getElementById(canvasId).getContext("2d");

    // 0 - .99, describes how far along snake is between coordinates
    this.progress = 0;
}

erase() {
    for (let i = 0; i < this.coordinates.length; i++) {
        let c1 = this.coordinates[i][0],
            c2 = this.coordinates[i][1];
        this.ctx.clearRect(c1 * 31, c2 * 31, 31, 31);
    }
}

next() {
    this.progress += 0.01;

    if (this.progress >= 1) {
        this.progress %= 1;

        let nextCoord = this.coordinates[4].slice();
        nextCoord[0] += ((this.direction % 2) * this.direction);
        nextCoord[1] += ((!(this.direction % 2) * (this.direction / 2)));
        this.coordinates.push(nextCoord);
        this.coordinates.shift();
    }
    console.log(this.erase);
    this.erase();
    this.draw();

}

}

So far, I can call AnimatedSnake.next() indefinitely if I'm doing it manually (i.e. from the console). However, when I put the function in an interval or timeout - setInterval(AnimatedSnake.next, 100) - it all of a sudden, on the first run, claims that AnimatedSnake.erase is not a function. I tried putting AnimatedSnake.erase() directly in the interval, and when I do THAT, for some absurd reason it goes and tells me that it cannot take the length property of AnimatedSnake.coordinates, which it claims is undefined. Nowhere in my code to I redefine any of these things. coordinates is altered, but it should not be undefined at any point. And erase is of course a method that I never change. Does anyone have any insight into why, when these are called with setInterval or setTimeout weird things happen, but if I call the functions repeatedly (even in a for loop) without the JavaScript timing functions everything works out fine? I'm genuinely stumped.

Elle Nolan
  • 379
  • 5
  • 8
  • 22
  • 1
    When you pass a function to `setIntverval` you loose the context that binds `this` because it just passes a function reference. You can try `setInterval(() => AnimatedSnake.next, 100)` or `setInterval(AnimatedSnake.next.bind(AnimatedSnake), 100)` to keep the correct context for the function call. – Mark Oct 17 '18 at 05:40
  • Where's the instance of AnimatedSnake? They aren't static methods to be used as `AnimatedSnake.next` – Sajal Preet Singh Oct 17 '18 at 05:42
  • @SajalPreetSingh I have an instance, I just felt I didn't need to explicitly show one to describe my problem. Don't worry :) – Elle Nolan Oct 17 '18 at 05:45

1 Answers1

3

Consider these two snippets:

animatedSnake.next()

And:

let method = animatedSnake.next;
method();

In the first snippet next is called as a member of animatedSnake object, so this within the context of next method refers to the animatedSnake object.

In the second snippet the next method is detached from the object, so this no longer refers to the animatedSnake instance when the method function is invoked. This is how passing a method to another function, like setInterval works. You can either use Function.prototype.bind method for setting the context manually:

setInterval(animatedSnake.next.bind(animatedSnake), 100)

or wrap the statement with another function:

setInterval(() => animatedSnake.next(), 100)
Ram
  • 143,282
  • 16
  • 168
  • 197
  • I'm gonna wrap it in another function - I probably should've thought of that when I was debugging, but I'm still glad I asked the question because I didn't realize that callbacks detached methods from objects/classes. Thanks for the explanation! – Elle Nolan Oct 17 '18 at 05:47
  • @ElleNolan You are welcome! Since the main topic is the `this` keyword, I think you may find answers of this question useful: [How does the “this” keyword work?](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – Ram Oct 17 '18 at 06:04