web-dev-qa-db-fra.com

"This" dans la méthode de classe es6

Pour une raison quelconque, j'obtiens des valeurs étranges pour "ceci" dans ma classe es6 ...

'use strict';
class Clicker {
  constructor(element) {
    this.count = 0;
    this.elem = element;
    this.elem.addEventListener('click', this.click);
    
    // logs Clicker { count:0, elem: button#thing} as expected
    console.log(this);
  }

  click() {
    // logs <button id="thing">...</button> as unexpected...
    console.log(this);
    this.count++;
  }
}


var thing = document.getElementById('thing');
var instance = new Clicker(thing);
<button id="thing">Click me</button>

Question:

Pourquoi le "ceci" à l'intérieur de la méthode click des Clickers fait-il référence au nœud dom plutôt qu'à ... lui-même?

Plus important encore, comment puis-je faire référence à la propriété count Clickers à partir de sa méthode click si je ne peux pas utiliser "this" pour le faire?

27
Andrew Luhring

Pourquoi le "ceci" à l'intérieur de la méthode click des Clickers fait-il référence au nœud dom plutôt qu'à ... lui-même?

Parce que la spécification de .addEventListener() est de définir le pointeur this sur l'élément DOM qui a intercepté l'événement. Voilà comment il est conçu pour fonctionner.


Lorsque vous passez une méthode en tant que rappel où vous souhaitez remplacer la valeur de this, vous pouvez utiliser .bind() pour forcer la valeur souhaitée de this avec:

this.elem.addEventListener('click', this.click.bind(this));

Explication:

Tous les appels de fonction en Javascript définissent une nouvelle valeur de this selon la façon dont la fonction est appelée. Voir cette explication pour plus d'informations sur cet ensemble de règles de base.

En plus de cela, lorsque vous faites cela:

this.elem.addEventListener('click', this.click);

Vous obtenez simplement la méthode this.click Et passez cette méthode seule à addEventListener(). La valeur de this sera complètement perdue. C'est comme si vous faisiez cela:

var m = this.click;     // m here is just a reference to Clicker.prototype.click
this.elem.addEventListener('click', m);

En plus de cela, .addEventListener() est spécialement conçu pour définir sa propre valeur de this lorsqu'il appelle le rappel (pour pointer this sur l'élément créant l'événement).

Ainsi, vous pouvez utiliser .bind() comme indiqué ci-dessus pour forcer la valeur appropriée de this à être en place lorsque votre méthode est appelée.


Pour référence, vous pouvez trouver cette description des six façons dont this est défini pour qu'un appel de fonction en Javascript soit utile.


Autres options

Je trouve que .bind() est le moyen le plus clair de le définir, mais vous pouvez également utiliser une fonction anonyme locale:

var self = this;
this.elem.addEventListener('click', function() {
    self.click();
});

ou dans ES6, une fonction flèche:

this.elem.addEventListener('click', () => this.click());

La fonction flèche conservera automatiquement la valeur de this pour éviter d'avoir besoin de la référence self utilisée dans l'exemple précédent.

30
jfriend00