Reputation: 399
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.
Upvotes: 1
Views: 71
Reputation: 144679
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)
Upvotes: 3