A closure-based listener is never removed, keeping the whole Widget alive in memory.
Codejavascript
class Widget {
constructor(el) {
this.el = el;
this.data = new Array(100000).fill(0);
el.addEventListener('click', () => this.handleClick());
}
handleClick() {
console.log('clicked', this.data.length);
}
destroy() {
this.el.removeEventListener('click', () => this.handleClick());
this.el = null;
}
}
// Usage in a long-lived SPA:
let w = new Widget(document.getElementById('btn'));
w.destroy();
w = null; // expecting the Widget and its 100k-array to be collected
Why does the Widget (and its large `data` array) leak even after `destroy()` and `w = null`?