Classe ES6: accesso a “questo” con “addEventListener” applicato al metodo

In questo script es6, l’evento click non funziona perché il metodo sayHello viene chiamato con this.elm (

) come this .

come associare un evento a un metodo senza perdere l’ambito?

 class player{ constructor(name){ this.name = name; this.elm = document.createElement('div'); this.elm.addEventListener('click', this.sayHello); } sayHello(){ console.log(this.name + ' say: "hello!"'); // 'undefined say 'hello!"'; } kill(){ console.log(`RIP ${this.name} :'(`); this.elm.addClass('dead'); this.elm.removeEventListener('click', this.sayHello); } } 

Questo è un problema generale di JS, ma il nocciolo della questione è questo

 this.elm.addEventListener('click', this.sayHello); 

non è diverso da

 var fn = this.sayHello; this.elm.addEventListener('click', fn); 

Stai passando una funzione come gestore di eventi, ma non hai assicurato che quando viene chiamato fn this sarà impostato sul valore desiderato. Il modo più semplice per farlo in ES5 sarebbe

 this.elm.addEventListener('click', this.sayHello.bind(this)); 

o in ES6, utilizzando una funzione freccia:

 this.elm.addEventListener('click', evt => this.sayHello(evt)); 

Si noti tuttavia che entrambe queste soluzioni interromperanno la logica (già leggermente interrotta) in kill perché

 this.elm.removeEventListener('click', /* what? */); 

Non hai più alcun riferimento alla funzione che hai allegato, quindi non hai modo di rimuovere il gestore di eventi.

Suggerirei due opzioni:

 // Create a new function that is bound, and give it a new name // so that the 'this.sayHello()' call still works. this.boundSayHello = evt => this.sayHello(evt); this.elm.addEventListener('click', this.boundSayHello); this.elm.removeEventListener('click', this.boundSayHello); 

o

 // Bind the function with the same name and use `.bind` instead of the // arrow function option. this.sayHello = this.sayHello.bind(this); this.elm.addEventListener('click', this.sayHello); this.elm.removeEventListener('click', this.sayHello);