Usando jQuery $ (this) com funções de seta ES6 (lexical esta ligação)

127

O uso de funções de seta ES6 com thisencadernação lexical é ótimo.

No entanto, deparei-me com um problema atrás, usando-o com uma ligação típica de clique em jQuery:

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

Usando uma função de seta:

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

E, em seguida, $(this)é convertido em fechamento do tipo ES5 (self = this).

É uma maneira de Traceur ignorar "$ (this)" para ligação lexical?

JRodl3r
fonte
esse parece ser um exemplo perfeito de quando não usar uma função de seta, pois .on()realmente tem um thisvalor útil para você. Para mim, é muito mais claro thisreferir-se ao destino do evento do que ter que passar no evento e encontrar o destino manualmente. Eu não brinquei muito com as funções de seta, mas parece que seria confuso ir e voltar com funções anônimas.
Robisrob

Respostas:

193

Isso não tem nada a ver com o Traceur e desativar algo, é simplesmente assim que o ES6 funciona. É a funcionalidade específica que você está solicitando usando em =>vez de function () { }.

Se você deseja escrever o ES6, precisa escrever o ES6 o tempo todo, não pode entrar e sair dele em determinadas linhas de código e, definitivamente, não pode suprimir ou alterar a maneira como =>funciona. Mesmo que você pudesse, você acabaria com uma versão bizarra do JavaScript que somente você entende e que nunca funcionaria corretamente fora do seu Traceur personalizado, o que definitivamente não é o objetivo do Traceur.

A maneira de resolver esse problema específico não é usar thispara obter acesso ao elemento clicado, mas usar event.currentTarget:

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

O jQuery fornece event.currentTargetespecificamente porque, mesmo antes do ES6, nem sempre é possível para o jQuery impor uma thisfunção de retorno de chamada (ou seja, se ele estava vinculado a outro contexto via bind.

magro
fonte
4
Observe que, apesar de divergir apenas para .onchamadas delegadas , thisna verdade é event.currentTarget.
loganfsmyth
Esta resposta está ok? Como loganfsmyth observado, this== event.currentTarget. Não?
Léon Pelletier
3
@ LéonPelletier No. thise event.currentTargetsão os mesmos, a menos que thisestejam ligados ao escopo anexo, como acontece com uma função de seta ES6.
meagar
8
se você quiser economizar algum código, você também pode também desestruturar-lo: ({currentTarget}) => {$ (currentTarget) .addClass ( 'activo')}
Frank
55

Ligação de evento

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

Ciclo

Array.prototype.forEach.call($items, (el, index, obj) => {
    var $this = $(el);
    // ... deal with $this
});
Ryan Huang
fonte
Procurando $jQueryElements.each()? jQuery realmente envia alguns argumentos para cada objeto, para que você não precise disso => ​​É$(...).each((index, el) => console.log(el))
jave.web
53

Outro caso

A resposta principal está correta e eu votei positivamente.

No entanto, há outro caso:

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

Pode ser corrigido como:

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

Este é um erro histórico no jQuery que coloca o índice , em vez do elemento como o primeiro argumento:

.each (função)


Tipo de função : Function( Integer index, Element element )
Uma função a ser executada para cada elemento correspondente.

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

Tyler Long
fonte
1
O mesmo para fucntions like #$('jquery-selector').map
Nicholas Siegmundt
Isso foi super útil para mim usar em coisas como $ ('jquery-selector'). Filter etc ... obrigado por deixar isso claro.
R Jones
8

(Esta é uma resposta que eu escrevi para outra versão desta pergunta, antes de aprender que era uma duplicata desta pergunta. Acho que a resposta reúne as informações com bastante clareza, então decidi adicioná-las como um wiki da comunidade, embora seja amplamente diferente formulação das outras respostas.)

Você não pode. Isso é metade do ponto das funções das setas, elas fecham em thisvez de ter as suas próprias, definidas pela forma como são chamadas. Para o caso de uso da pergunta, se você desejar thisdefinir pelo jQuery ao chamar o manipulador, o manipulador precisará ser uma functionfunção.

Mas se você tiver um motivo para usar uma seta (talvez você queira usar thiso que significa fora da seta), poderá usar em e.currentTargetvez de, thisse quiser:

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

O currentTargetobjeto on the event é igual ao que o jQuery define thisao chamar seu manipulador.

TJ Crowder
fonte
5

Como Meager disse em sua resposta sobre a mesma pergunta: se você deseja escrever o ES6, precisa escrever o ES6 o tempo todo ,

portanto, se você estiver usando a função de seta do ES6:, (event)=>{}precisará usar em $(event.currentTarget)vez de $(this).

você também pode usar uma maneira mais agradável e limpa de usar o currentTarget como ({currentTarget})=>{},

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

originalmente essa idéia foi comentada por rizzi frank na resposta de @ Meager, e eu achei útil e acho que nem todas as pessoas lerão esse comentário, então eu o escrevi como outra resposta.

Haritsinh Gohil
fonte