In questo script es6, l’evento click non funziona perché il metodo sayHello
viene chiamato con this.elm
(
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);