Dans ce script es6, l'événement click ne fonctionne pas car la méthode sayHello
est appelée avec this.Elm
(<div>
) comme this
.
comment associer un événement à une méthode sans perdre la portée?
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);
}
}
C’est une question générale du JS, mais le cœur de celle-ci est que
this.Elm.addEventListener('click', this.sayHello);
n'est pas différent de
var fn = this.sayHello;
this.Elm.addEventListener('click', fn);
Vous transmettez une fonction en tant que gestionnaire d'événements, mais vous ne vous êtes pas assuré que, lorsque fn
serait appelé, this
serait alors défini sur la valeur souhaitée. La manière la plus simple de le faire dans ES5 serait de
this.Elm.addEventListener('click', this.sayHello.bind(this));
ou dans ES6, en utilisant une fonction de flèche:
this.Elm.addEventListener('click', evt => this.sayHello(evt));
Notez cependant que ces deux solutions vont casser votre logique (déjà légèrement cassée) dans kill
parce que
this.Elm.removeEventListener('click', /* what? */);
Vous n'avez plus aucune référence à la fonction que vous avez attachée, vous n'avez donc aucun moyen de supprimer le gestionnaire d'événements.
Je suggérerais deux options:
// 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);
ou
// 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);