javascript - Bruke jQuery $ (this) med ES6 Arrow Functions (leksikalsk this-binding)


Å bruke ES6 pilfunksjoner med leksikalsk this-binding er flott.

Men jeg støtte på et problem for et øyeblikk siden da jeg brukte det med en typisk jQuery click-binding:

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

Ved å bruke en pilfunksjon i stedet:

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

Og så blir $ (this) konvertert til en ES5 (self=this) type lukking.

Finnes det en måte å få Traceur til å ignorere "$ (this)" for leksikalsk binding?

Svar #1

Dette har ingenting å gjøre med Traceur og å slå av noe; dette er rett og slett hvordan ES6 fungerer. Det er den spesifikke funksjonaliteten du spør etter ved å bruke => i stedet for function() { }.

Hvis du vil skrive ES6, må du skrive ES6 hele tiden. Du kan ikke bytte frem og tilbake på visse kodelinjer, og du kan definitivt ikke undertrykke eller endre måten => fungerer på. Selv om du kunne, ville du bare ende opp med en merkelig versjon av JavaScript som bare du forstår og som aldri ville fungere korrekt utenfor din tilpassede Traceur, noe som definitivt ikke er poenget med Traceur.

Måten å løse dette spesifikke problemet på er ikke å bruke this for å få tilgang til det klikkede elementet, men i stedet bruke event.currentTarget:

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

jQuery gir event.currentTarget spesielt fordi det, selv før ES6, ikke alltid er mulig for jQuery å pålegge en this på tilbakeringingsfunksjonen (dvs. hvis den var bundet til en annen kontekst via bind.

Svar #2

Hendelsesbinding

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

Løkke

Array.prototype.forEach.call($items, (el, index, obj) => {
    var $this = $(el);
    // ... deal with $this
});

Svar #3

En annen sak

Svaret fra meagar er korrekt, og jeg har stemt det opp.

Men det finnes en annen sak:

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

Kan fikses som:

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

Dette er en historisk feil i jQuery som setter indeksen, i stedet for elementet som det første argumentet:

.each( funksjon )

funksjon
Type: Funksjon( Integer indeks, Element element )
En funksjon som skal utføres for hvert samsvarende element.

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

Gjelder også for .map( function ) og .filter( function ).

Svar #4

Som Meager sa i sitt svar på dette samme spørsmålet: Hvis du vil skrive ES6, må du skrive ES6 hele tiden,

så hvis du bruker pilfunksjon fra ES6: (event)=>{}, da må du bruke $ (event.currentTarget) i stedet for $ (this).

du kan også bruke en finere og renere måte å bruke currentTarget på som ({currentTarget})=>{},

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

Opprinnelig ble denne ideen kommentert av Rizzi Frank i Meagars svar, og jeg syntes den var nyttig, og jeg tror ikke at alle vil lese den kommentaren, så jeg har skrevet den som dette andre svaret.

Relaterte artikler