Verwenden von jQuery $ (this) mit ES6-Pfeilfunktionen (lexikalisch diese Bindung)

127

Die Verwendung von ES6-Pfeilfunktionen mit lexikalischer thisBindung ist großartig.

Vor kurzem bin ich jedoch auf ein Problem gestoßen, das ich mit einer typischen jQuery-Klickbindung verwendet habe:

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

Verwenden Sie stattdessen eine Pfeilfunktion:

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

Und wird dann $(this)in einen ES5-Verschluss (self = this) konvertiert.

Kann Traceur "$ (this)" für die lexikalische Bindung ignorieren?

JRodl3r
quelle
Dies scheint ein perfektes Beispiel dafür zu sein, wann Sie keine Pfeilfunktion verwenden sollten, da .on()dies tatsächlich einen thisfür Sie nützlichen Wert hat. Für mich ist es viel klarer, thissich auf das Ereignisziel zu beziehen, als das Ereignis zu bestehen und das Ziel manuell zu finden. Ich habe nicht viel mit Pfeilfunktionen gespielt, aber es scheint verwirrend, mit anonymen Funktionen hin und her zu gehen.
Robisrob

Antworten:

193

Das hat nichts mit Traceur zu tun und etwas auszuschalten. So funktioniert ES6 einfach. Es ist die spezifische Funktionalität, nach der Sie fragen, indem Sie =>statt verwenden function () { }.

Wenn Sie ES6 schreiben möchten, müssen Sie ständig ES6 schreiben, Sie können in bestimmten Codezeilen nicht ein- und ausschalten und Sie können die Funktionsweise definitiv nicht unterdrücken oder ändern =>. Selbst wenn Sie könnten, würden Sie nur mit einer bizarren Version von JavaScript enden, die nur Sie verstehen und die außerhalb Ihres angepassten Traceur niemals richtig funktionieren würde, was definitiv nicht der Sinn von Traceur ist.

Die Lösung dieses speziellen Problems besteht nicht darin this, Zugriff auf das angeklickte Element zu erhalten, sondern event.currentTarget:

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

jQuery bietet event.currentTargetspeziell, weil es jQuery noch vor ES6 nicht immer möglich ist, thisder Rückruffunktion ein a aufzuerlegen (dh, wenn es über an einen anderen Kontext gebunden war bind.

meagar
quelle
4
Beachten Sie, obwohl es nur für delegierte .onAnrufe abweicht , thisist es tatsächlich event.currentTarget.
Loganfsmyth
Ist diese Antwort in Ordnung? Wie loganfsmyth feststellte, this==event.currentTarget . Nein?
Léon Pelletier
3
@ LéonPelletier Nr. thisUndevent.currentTarget sind dieselben, sofern thissie nicht an den umschließenden Bereich gebunden sind, wie bei einer ES6-Pfeilfunktion.
Meagar
8
Wenn Sie Code speichern möchten, können Sie ihn auch zerstören: ({currentTarget}) => {$ (currentTarget) .addClass ('active')}
Frank
55

Ereignisbindung

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

Schleife

Array.prototype.forEach.call($items, (el, index, obj) => {
    var $this = $(el);
    // ... deal with $this
});
Ryan Huang
quelle
Auf der Suche nach $jQueryElements.each()? jQuery sendet tatsächlich einige Argumente an jedes Objekt, sodass Sie diese überhaupt nicht benötigen => It's$(...).each((index, el) => console.log(el))
jave.web
53

Ein anderer Fall

Die Top-Antwort ist richtig und ich habe sie hochgestimmt.

Es gibt jedoch einen anderen Fall:

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

Könnte behoben werden als:

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

Dies ist ein historischer Fehler in jQuery, bei dem der Index anstelle des Elements als erstes Argument verwendet wird:

.each (Funktion)

Funktionstyp
: Function( Integer index, Element element )
Eine Funktion, die für jedes übereinstimmende Element ausgeführt werden soll.

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

Tyler Long
quelle
1
Gleiches gilt für Funktionen wie$('jquery-selector').map
Nicholas Siegmundt
Dies war sehr nützlich für mich, um es in Dingen wie $ ('jquery-selector') zu verwenden. Filter etc ... danke, dass du es so klar gemacht hast.
R Jones
8

(Dies ist eine Antwort, die ich für eine andere Version dieser Frage geschrieben habe, bevor ich erfuhr, dass es sich um ein Duplikat dieser Frage handelt. Ich denke, die Antwort fasst die Informationen ziemlich klar zusammen, daher habe ich beschlossen, sie als Community-Wiki hinzuzufügen, obwohl sie größtenteils nur anders ist Formulierung der anderen Antworten.)

Das kannst du nicht. Das ist die Hälfte der Pfeilfunktionen, die sie schließen, thisanstatt ihre eigenen zu haben, die durch ihre Bezeichnung festgelegt werden. Für den Anwendungsfall in der Frage thismüsste der Handler a sein , wenn Sie beim Aufrufen des Handlers von jQuery festlegen möchtenfunction Funktion sein .

Wenn Sie jedoch einen Grund für die Verwendung eines Pfeils haben (vielleicht möchten Sie ihn thisfür das verwenden, was er außerhalb des Pfeils bedeutet), können Sie ihn verwenden, e.currentTargetanstatt, thiswenn Sie möchten :

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

Das currentTargetObjekt on the event entspricht dem, was jQuery thisbeim Aufrufen Ihres Handlers festlegt .

TJ Crowder
quelle
5

Wie Meager in seiner Antwort auf dieselbe Frage sagte Wenn Sie ES6 schreiben möchten, müssen Sie ständig ES6 schreiben .

Wenn Sie also die Pfeilfunktion von ES6: verwenden (event)=>{}, müssen Sie $(event.currentTarget)stattdessen verwenden$(this) .

Sie können auch eine schönere und sauberere Art der Verwendung von currentTarget verwenden als ({currentTarget})=>{},

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

Ursprünglich wurde diese Idee von Rizzi Frank in @ Meagers Antwort kommentiert , und ich fand sie nützlich und ich denke, dass nicht alle Leute diesen Kommentar lesen werden, also habe ich ihn als diese andere Antwort geschrieben.

Haritsinh Gohil
quelle