In the following code, I would expect printHello
to be called twice (once from go()
and once from runTask()
):
class Hello {
task = undefined;
runTask() {
console.log("Task is", this.task);
this.task();
}
printHello() {
console.log("Hello");
}
go() {
this.task = this.printHello;
console.log("Set task to", this.task);
setTimeout(this.runTask, 0); // Fails
// setTimeout(() => this.runTask(), 0); // Works
}
};
const hello = new Hello();
hello.go(); // Says `this.task` is undefined, but then...
hello.runTask(); // ... running it manually works fine
In my mind:
- I create an instance of the class
- Then calling
go()
- Sets the
task
field/property on that instance toprintHello
- Sets up a request to
runTask
after the timeout
- Sets the
I would expect that runTask
would be called with task
set to printHello
, but it's actually undefined
in the setTimeout
call. However, if I just call runTask
directly on my hello
instance it works fine. Also, if I replace the setTimeout
call with a lambda it works fine.
It seems clear it's a stale closure type of issue, I just don't have a great mental model or rulebook that would prevent me from writing code like this in the future and then be perplexed about why it wasn't working.
I was thinking that this
would be captured when passing runTask
, which should then point to a valid task, but that's not the case.
I'd really appreciate some insight about exactly why this doesn't work and requires the lambda version to be used.