Utilisation de jQuery $ (this) avec les fonctions fléchées ES6 (lexical this binding)

129

L'utilisation des fonctions fléchées ES6 avec la thisliaison lexicale est excellente.

Cependant, j'ai rencontré un problème il y a un instant en l'utilisant avec une liaison de clic jQuery typique:

class Game {
  foo() {
    self = this;
    this._pads.on('click', function() {
      if (self.go) { $(this).addClass('active'); }
    });
  }
}

En utilisant une fonction de flèche à la place:

class Game {
  foo() {
    this._pads.on('click', () => {
      if (this.go) { $(this).addClass('active'); }
    });
  }
}

Et puis $(this)est converti en fermeture de type ES5 (self = this).

Est-il possible que Traceur ignore "$ (this)" pour la liaison lexicale?

JRodl3r
la source
cela semble être un exemple parfait de ne pas utiliser de fonction fléchée car a en .on()effet une thisvaleur utile pour vous. Pour moi, il est beaucoup plus clair de se thisréférer à la cible de l'événement que d'avoir à passer l'événement et à trouver la cible manuellement. Je n'ai pas beaucoup joué avec les fonctions fléchées, mais il semble que ce serait déroutant de faire des allers-retours avec des fonctions anonymes.
robisrob

Réponses:

194

Cela n'a rien à voir avec Traceur et la désactivation de quelque chose, c'est simplement ainsi que fonctionne l'ES6. C'est la fonctionnalité spécifique que vous demandez en utilisant à la =>place de function () { }.

Si vous voulez écrire ES6, vous devez écrire ES6 tout le temps, vous ne pouvez pas y basculer et en sortir sur certaines lignes de code, et vous ne pouvez certainement pas supprimer ou modifier le =>fonctionnement. Même si vous le pouviez, vous vous retrouveriez avec une version bizarre de JavaScript que vous seul comprenez et qui ne fonctionnerait jamais correctement en dehors de votre Traceur personnalisé, ce qui n'est certainement pas le but de Traceur.

La façon de résoudre ce problème particulier n'est pas d'utiliser thispour accéder à l'élément cliqué, mais d'utiliser à la place event.currentTarget:

Class Game {
  foo(){
    this._pads.on('click', (event) => {
      if(this.go) {
        $(event.currentTarget).addClass('active');
      }
    });
  }
}

jQuery fournit event.currentTargetspécifiquement parce que, même avant ES6, il n'est pas toujours possible pour jQuery d'imposer un thisà la fonction de rappel (c'est-à-dire s'il était lié à un autre contexte via bind.

meagar
la source
4
Notez, bien qu'il ne diverge que pour les .onappels délégués , thisest en fait event.currentTarget.
loganfsmyth
Cette réponse est-elle correcte? Comme loganfsmyth noté, this== event.currentTarget. Non?
Léon Pelletier
3
@ LéonPelletier No. thiset event.currentTargetsont les mêmes sauf si elle thisest liée à la portée englobante, comme avec une fonction flèche ES6.
meagar
8
si vous souhaitez enregistrer du code, vous pouvez également le déstructurer: ({currentTarget}) => {$ (currentTarget) .addClass ('active')}
Frank
55

Liaison d'événement

$button.on('click', (e) => {
    var $this = $(e.currentTarget);
    // ... deal with $this
});

Boucle

Array.prototype.forEach.call($items, (el, index, obj) => {
    var $this = $(el);
    // ... deal with $this
});
Ryan Huang
la source
Vous cherchez $jQueryElements.each()? jQuery envoie en fait des arguments à chaque objet afin que vous n'en ayez pas besoin du tout => C'est$(...).each((index, el) => console.log(el))
jave.web
53

Un autre cas

La première réponse est correcte et je l'ai votée à la hausse.

Cependant, il y a un autre cas:

$('jquery-selector').each(() => {
    $(this).click();
})

Peut être corrigé comme:

$('jquery-selector').each((index, element) => {
    $(element).click();
})

Il s'agit d'une erreur historique dans jQuery qui met l' index , au lieu de l' élément comme premier argument:

.each (fonction)


Type de fonction : Function( Integer index, Element element )
une fonction à exécuter pour chaque élément correspondant.

Voir: https://api.jquery.com/each/#each-function

Tyler Long
la source
1
Idem pour des fonctions comme$('jquery-selector').map
Nicholas Siegmundt
Cela m'a été très utile à utiliser dans des choses comme $ ('jquery-selector'). Filter etc ... merci de le rendre si clair.
R Jones
8

(C'est une réponse que j'ai écrite pour une autre version de cette question, avant d'apprendre que c'était un double de cette question. Je pense que la réponse rassemble les informations assez clairement, alors j'ai décidé de l'ajouter en tant que wiki de la communauté, bien que ce soit en grande partie juste différent formulation des autres réponses.)

Vous ne pouvez pas. C'est la moitié du point des fonctions fléchées, elles se ferment au thislieu d'avoir leurs propres fonctions définies par la façon dont elles sont appelées. Pour le cas d'utilisation de la question, si vous souhaitez thisdéfinir par jQuery lors de l'appel du gestionnaire, le gestionnaire doit être une functionfonction.

Mais si vous avez une raison d'utiliser une flèche (peut-être voulez-vous utiliser thispour ce que cela signifie en dehors de la flèche), vous pouvez utiliser à la e.currentTargetplace de thissi vous le souhaitez:

class Game {
  foo(){
    this._pads.on('click', e => {                   // Note the `e` argument
      if(this.go) {
        $(e.currentTarget).addClass('active');      // Using it
      }
    });
  }
}

L'objet currentTargeton the event est le même que celui défini par jQuery thislors de l'appel de votre gestionnaire.

TJ Crowder
la source
5

Comme l'a dit Meager dans sa réponse à cette même question Si vous voulez écrire ES6, vous devez écrire ES6 tout le temps ,

donc si vous utilisez la fonction fléchée de ES6:, (event)=>{}vous devez utiliser à la $(event.currentTarget)place de $(this).

vous pouvez également utiliser une manière plus agréable et plus propre d'utiliser currentTarget comme ({currentTarget})=>{},

Class Game {
  foo(){
    this._pads.on('click', ({currentTarget}) => {
      if(this.go) {
        $(currentTarget).addClass('active');
      }
    });
  }
}

à l'origine, cette idée a été commentée par rizzi frank dans la réponse de @ Meager, et je l'ai jugée utile et je pense que tout le monde ne lira pas ce commentaire, alors je l'ai écrit comme une autre réponse.

Haritsinh Gohil
la source