Why does this in JavaScript still trip up senior devs?
- javascript
I watched an engineer with twelve years of experience lose twenty minutes to a this bug last week. Not a junior. Someone who has shipped more production code than most people ever will.
That keeps happening, and I don't think it's because this is difficult.
The actual rule
this is not bound when a function is defined. It's bound when a function is called, and it's determined by what sits to the left of the dot at the call site.
const logger = {
prefix: "[app]",
log(message) {
console.log(this.prefix, message);
},
};
logger.log("hello");
// [app] hello ← `logger` is left of the dot
const log = logger.log;
log("hello");
// undefined hello ← nothing is left of the dotNothing about log changed. The function is identical. Only the call site moved, and the call site is the whole story.
Where it actually bites
Nobody writes the example above. What people write is this:
class RetryQueue {
constructor() {
this.pending = [];
}
flush() {
// `this` is lost — setTimeout calls the callback with no receiver
setTimeout(this.drain, 1000);
}
drain() {
console.log(this.pending.length); // TypeError
}
}You never wrote a detached reference. You passed a method to an API, and that API called it later with no receiver. Same bug, wearing a costume.
Arrow functions fix it because they don't have their own this at all — they close over whatever this was where they were written:
flush() {
setTimeout(() => this.drain(), 1000);
}The reason it keeps catching people
Modern JavaScript lets you go a long time without thinking about this. Hooks instead of class components. Modules instead of namespace objects. Closures instead of methods. this mostly disappeared from the code we write day to day.
So the knowledge doesn't decay because it's hard. It decays because it's unused — and then it resurfaces inside a callback, in someone else's library, at 4pm on a Friday.
The rule fits in one line. Read the call site, look left of the dot. The hard part was never understanding it. The hard part is remembering to ask.