Usando jQuery $ (esto) con funciones de flecha ES6 (léxico este enlace)

129

Usar las funciones de flecha de ES6 con thisenlace léxico es genial.

Sin embargo, me encontré con un problema hace un momento al usarlo con un enlace de clic típico de jQuery:

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

Usando una función de flecha en su lugar:

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

Y luego $(this)se convierte a cierre de tipo ES5 (self = this).

¿Es una forma de hacer que Traceur ignore "$ (this)" para el enlace léxico?

JRodl3r
fuente
esto parece un ejemplo perfecto de cuándo no usar una función de flecha, ya .on()que de hecho tiene un thisvalor útil para usted. Para mí, es mucho más claro thisreferirse al objetivo del evento que tener que pasar el evento y encontrar el objetivo manualmente. No he jugado mucho con las funciones de flecha, pero parece que sería confuso ir y venir con funciones anónimas.
robisrob

Respuestas:

194

Esto no tiene nada que ver con Traceur y apagar algo, así es simplemente como funciona ES6. Es la funcionalidad específica que está pidiendo usar en =>lugar de function () { }.

Si desea escribir ES6, necesita escribir ES6 todo el tiempo, no puede entrar y salir de él en ciertas líneas de código, y definitivamente no puede suprimir o alterar la forma en que =>funciona. Incluso si pudiera, terminaría con una versión extraña de JavaScript que solo usted entiende y que nunca funcionaría correctamente fuera de su Traceur personalizado, que definitivamente no es el objetivo de Traceur.

La forma de resolver este problema en particular no es usar thispara obtener acceso al elemento en el que se hizo clic, sino usar event.currentTarget:

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

jQuery proporciona event.currentTargetespecíficamente porque, incluso antes de ES6, no siempre es posible que jQuery imponga un thisen la función de devolución de llamada (es decir, si estaba vinculado a otro contexto a través de bind.

meagar
fuente
4
Tenga en cuenta que, aunque solo diverge para .onllamadas delegadas , en thisrealidad lo es event.currentTarget.
loganfsmyth
¿Está bien esta respuesta? Como señaló loganfsmyth, this== event.currentTarget. ¿No?
Léon Pelletier
3
@ LéonPelletier No. thisy event.currentTargetson los mismos a menos thisque estén vinculados al alcance adjunto, como con una función de flecha ES6.
meagar
8
si desea guardar algún código, también puede desestructurarlo: ({currentTarget}) => {$ (currentTarget) .addClass ('active')}
Frank
55

Enlace de eventos

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

Lazo

Array.prototype.forEach.call($items, (el, index, obj) => {
    var $this = $(el);
    // ... deal with $this
});
Ryan Huang
fuente
Buscando $jQueryElements.each()? jQuery en realidad envía algunos argumentos a cada objeto, por lo que no lo necesita en absoluto => Es$(...).each((index, el) => console.log(el))
jave.web
53

Otro caso

La respuesta principal es correcta y la he votado.

Sin embargo, hay otro caso:

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

Podría arreglarse como:

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

Este es un error histórico en jQuery que coloca el índice , en lugar del elemento, como primer argumento:

.each (función)


tipo de función : Function( Integer index, Element element )
una función que se ejecutará para cada elemento coincidente.

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

Tyler Long
fuente
1
Lo mismo para funciones como$('jquery-selector').map
Nicholas Siegmundt
Esto fue muy útil para mí para usarlo en cosas como $ ('jquery-selector'). Filter, etc. gracias por dejarlo tan claro.
R Jones
8

(Esta es una respuesta que escribí para otra versión de esta pregunta, antes de saber que era un duplicado de esta pregunta. Creo que la respuesta reúne la información con bastante claridad, así que decidí agregarla como un wiki de la comunidad, aunque es en gran parte diferente redacción de las otras respuestas.)

No puedes. Eso es la mitad de las funciones de punta de flecha, se cierran en thislugar de tener las suyas propias que se establecen según la forma en que se llaman. Para el caso de uso de la pregunta, si desea thisque jQuery lo establezca al llamar al controlador, el controlador debería ser una functionfunción.

Pero si tiene una razón para usar una flecha (quizás quiera usarla thispor lo que significa fuera de la flecha), puede usar en e.currentTargetlugar de thissi lo desea:

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

El currentTargetobjeto de evento on es el mismo que jQuery establece thiscuando llama a su controlador.

TJ Crowder
fuente
5

Como dijo Meager en su respuesta a esta misma pregunta, si desea escribir ES6, debe escribir ES6 todo el tiempo ,

por lo que si está usando la función de flecha de ES6:, (event)=>{}entonces debe usar en $(event.currentTarget)lugar de $(this).

también puede usar una forma más agradable y limpia de usar currentTarget como ({currentTarget})=>{},

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

originalmente, esta idea fue comentada por rizzi frank en la respuesta de @ Meager, y la sentí útil y creo que no todas las personas leerán ese comentario, así que lo escribí como esta otra respuesta.

Haritsinh Gohil
fuente