dev3 ·
class Counter {
count = 0;
inc() { this.count++; }
}
const c = new Counter();
button.addEventListener('click', c.inc);
Clicking gives Cannot read properties of undefined (reading 'count'). Why?
0
DEV3 Developer Forum
Every post is reviewed first. Usually reviewed within 24 hours.
class Counter {
count = 0;
inc() { this.count++; }
}
const c = new Counter();
button.addEventListener('click', c.inc);
Clicking gives Cannot read properties of undefined (reading 'count'). Why?
this is decided by how a function is called, not where it is defined (except arrow functions).
new Fn(): this is the new object.fn.call(obj), apply, bind(obj): this is obj.obj.method(): this is obj.fn(): this is undefined in strict mode (modules and classes are strict), otherwise the global object.this; they capture it from the surrounding scope.button.addEventListener('click', c.inc) passes the function by itself. When the browser calls it, it is a plain call with this set to the element (or undefined for class code), not c.
// 1. bind
button.addEventListener('click', c.inc.bind(c));
// 2. wrapper arrow
button.addEventListener('click', () => c.inc());
// 3. arrow class field (each instance gets its own bound function)
class Counter {
count = 0;
inc = () => { this.count++; };
}
const o = { name: 'a', hi() { return this.name; } };
const f = o.hi;
f(); // undefined, lost the receiver
setTimeout(o.hi, 0); // also lost
setTimeout(() => o.hi(), 0); // fine
Do not use arrow functions as object methods when you need this to be the object.
Pitfall: bind creates a new function each call, so removeEventListener(type, c.inc.bind(c)) does not remove anything. Store the bound reference.