FunçÔes da seta JavaScript: por que são necessårias, como lidar com elas, quando uså-las e quando não

Uma das inovaçÔes mais notĂĄveis ​​do JavaScript moderno Ă© o aparecimento de funçÔes de seta, que Ă s vezes sĂŁo chamadas de funçÔes de seta "gordas". Ao declarar essas funçÔes, eles usam uma combinação especial de caracteres - => .

As funçÔes de seta tĂȘm duas vantagens principais sobre as funçÔes tradicionais. O primeiro Ă© uma sintaxe muito conveniente e compacta. A segunda Ă© que a abordagem para trabalhar com this nas funçÔes de seta parece mais intuitiva do que nas funçÔes comuns.

imagem

Às vezes, essas e outras vantagens levam ao fato de que a sintaxe da seta recebe uma preferĂȘncia incondicional sobre outras formas de declarar funçÔes. Por exemplo, a popular configuração de eslint do Airbnb força que sempre que uma função anĂŽnima Ă© criada, essa função seria do tipo flecha.

No entanto, como outros conceitos e mecanismos usados ​​na programação, as funçÔes de seta tĂȘm seus prĂłs e contras. Seu uso pode causar efeitos colaterais negativos. Para usar as funçÔes de seta corretamente, vocĂȘ precisa conhecer os possĂ­veis problemas associados a elas.

O material, cuja tradução publicamos hoje, se concentrarå em como as funçÔes de seta funcionam. Aqui, consideraremos situaçÔes em que seu uso pode melhorar o código e situaçÔes em que eles não devem ser usados.

Apresenta funçÔes de seta em JavaScript


As funçÔes de seta no JavaScript são algo como funçÔes lambda em Python e blocos em Ruby.

Essas sĂŁo funçÔes anĂŽnimas com uma sintaxe especial que recebem um nĂșmero fixo de argumentos e funcionam no contexto do escopo que os inclui, ou seja, no contexto da função ou outro cĂłdigo no qual eles sĂŁo declarados.

Vamos falar sobre isso com mais detalhes.

Arrow FunçÔes de seta de sintaxe


As funçÔes de seta sĂŁo construĂ­das de acordo com um Ășnico esquema, enquanto a estrutura de funçÔes pode ser, em casos especiais, simplificada. A estrutura bĂĄsica da função de seta Ă© assim:

 (argument1, argument2, ... argumentN) => { //   } 

A lista de argumentos da função estĂĄ entre parĂȘnteses, seguida por uma seta composta de caracteres = e > e, em seguida, vem o corpo da função entre chaves.

Isso é muito semelhante ao funcionamento das funçÔes comuns, as principais diferenças são que a palavra-chave function é omitida aqui e uma seta é adicionada após a lista de argumentos.

Em certos casos, no entanto, funçÔes simples de seta podem ser declaradas usando construçÔes muito mais compactas.

Considere a sintaxe usada se o corpo da função for representado por uma Ășnica expressĂŁo. Ele permite que vocĂȘ fique sem colchetes que enquadram o corpo da função e elimina a necessidade de retornar explicitamente os resultados da avaliação de uma expressĂŁo, pois esse resultado serĂĄ retornado automaticamente. Por exemplo, pode ser assim:

 const add = (a, b) => a + b; 

Aqui estå outra variante da notação abreviada da função, usada quando a função possui apenas um argumento.

 const getFirst = array => array[0]; 

Como vocĂȘ pode ver, os parĂȘnteses que cercam a lista de argumentos sĂŁo omitidos aqui. AlĂ©m disso, o corpo da função, que neste exemplo Ă© representado por um Ășnico comando, tambĂ©m Ă© gravado sem colchetes. Mais tarde, falaremos mais sobre os benefĂ­cios de tais projetos.

Objetos de retorno e funçÔes de seta de registro curto


Ao trabalhar com funçÔes de seta, tambĂ©m sĂŁo usadas algumas construçÔes de sintaxe mais complexas, Ășteis para conhecer.

Por exemplo, tente usar uma expressĂŁo de linha Ășnica para retornar de uma função literal do objeto. Pode parecer, dado o que jĂĄ sabemos sobre as funçÔes de seta, que uma declaração de função serĂĄ semelhante a esta:

 (name, description) => {name: name, description: description}; 

O problema com este código é sua ambiguidade. Ou seja, as chaves que queremos usar para descrever o objeto literal parecem estar tentando incluir o corpo de uma função nelas.

Para indicar ao sistema que queremos dizer o objeto literal, precisamos incluĂ­-lo entre parĂȘnteses:

 (name, description) => ({name: name, description: description}); 

▍ FunçÔes de seta e seu contexto de execução


Diferentemente de outras funçÔes, as funçÔes de seta nĂŁo tĂȘm seu prĂłprio contexto de execução .

Na pråtica, isso significa que eles herdam as entidades this e arguments da função pai.

Por exemplo, compare as duas funçÔes apresentadas no código a seguir. Um deles é comum, o segundo é flecha.

 const test = { name: 'test object', createAnonFunction: function() {   return function() {     console.log(this.name);     console.log(arguments);   }; }, createArrowFunction: function() {   return () => {     console.log(this.name);     console.log(arguments);   }; } }; 

Hå um objeto de test com dois métodos. Cada um deles é uma função que cria e retorna uma função anÎnima. A diferença entre esses métodos é apenas que, no primeiro deles, a expressão funcional tradicional é usada e na função da segunda seta.

Se experimentarmos esse código no console, passando os mesmos argumentos para os métodos do objeto, embora os métodos pareçam muito semelhantes, obteremos resultados diferentes:

 > const anon = test.createAnonFunction('hello', 'world'); > const arrow = test.createArrowFunction('hello', 'world'); > anon(); undefined {} > arrow(); test object { '0': 'hello', '1': 'world' } 

Uma função anĂŽnima tem seu prĂłprio contexto, portanto, quando for chamada, quando vocĂȘ chamar test.name , o valor da propriedade name do objeto nĂŁo serĂĄ test.name e, quando vocĂȘ chamar arguments , a lista de argumentos da função usada para criar e retornar a função sob investigação nĂŁo serĂĄ exibida.

No caso de uma função de seta, verifica-se que seu contexto coincide com o contexto da função que a criou, o que lhe då acesso tanto à lista de argumentos transmitidos por essa função quanto à propriedade de name do objeto cujo método é essa função.

SituaçÔes em que as funçÔes de seta aprimoram o código


Processando listas de valores


FunçÔes lambda tradicionais, bem como funçÔes de seta, depois que aparecem em JavaScript, geralmente são usadas em situaçÔes em que uma determinada função é aplicada a cada elemento de uma determinada lista.

Por exemplo, se houver uma matriz de valores que precise ser convertida usando o método matrizes de map , uma função de seta é ideal para descrever essa conversão:

 const words = ['hello', 'WORLD', 'Whatever']; const downcasedWords = words.map(word => word.toLowerCase()); 

Aqui estå um exemplo extremamente comum do uso semelhante de funçÔes de seta, que consiste em trabalhar com as propriedades dos objetos:

 const names = objects.map(object => object.name); 

Da mesma forma, se em vez de tradicionais for loops, eles usam modernos loops forEach baseados em forEach , as funçÔes de seta usam this entidade pai, tornam seu uso intuitivo:

 this.examples.forEach(example => { this.runExample(example); }); 

▍ Promessas e cadeias de promessas


Outra situação em que as funçÔes de seta permitem escrever códigos mais limpos e compreensíveis é representada por construçÔes de software assíncronas.

Portanto, as promessas simplificam bastante o trabalho com cĂłdigo assĂ­ncrono. Ao mesmo tempo, mesmo se vocĂȘ preferir usar a construção assĂ­ncrona / aguardada , vocĂȘ nĂŁo pode prescindir das promessas , pois essa construção Ă© baseada nelas.

No entanto, ao usar promessas, vocĂȘ precisa declarar funçÔes chamadas apĂłs a conclusĂŁo do cĂłdigo assĂ­ncrono ou a conclusĂŁo da chamada assĂ­ncrona para uma determinada API.

Este é o local ideal para usar as funçÔes de seta, especialmente se a função resultante tiver um determinado estado, se referir a algo no objeto. Por exemplo, pode ser assim:

 this.doSomethingAsync().then((result) => { this.storeResult(result); }); 

▍ Transformação de Objetos


Outro caso de uso comum para funçÔes de seta é encapsular transformaçÔes de objeto.

Por exemplo, no Vue.js, existe um padrĂŁo comum para incluir fragmentos de armazenamento do Vuex diretamente em um componente do Vue usando o mapState .

Esta operação inclui declaraçÔes de um conjunto de "conversores" que selecionam exatamente o que é necessårio para um componente específico a partir do estado completo inicial.

Essas transformaçÔes simples são o lugar perfeito para usar as funçÔes de seta. Por exemplo:

 export default { computed: {   ...mapState({     results: state => state.results,     users: state => state.users,   }); } } 

SituaçÔes em que as funçÔes de seta não devem ser usadas


▍ MĂ©todos de objeto


Existem vårias situaçÔes em que o uso das funçÔes de seta não é uma boa ideia. As funçÔes de seta, se usadas de ùnimo leve, não apenas não ajudam os programadores, mas também se tornam uma fonte de problemas.

A primeira situação é usar funçÔes de seta como métodos de objeto. O contexto de execução e a this , específicos para funçÔes tradicionais, são importantes aqui.

Ao mesmo tempo, era popular usar uma combinação de propriedades de classe e funçÔes de seta para criar mĂ©todos com "ligação automĂĄtica", ou seja, aqueles que podem ser usados ​​por manipuladores de eventos, mas permanecem vinculados Ă  classe. Parecia algo assim:

 class Counter { counter = 0; handleClick = () => {   this.counter++; } } 

Usando uma construção semelhante, mesmo que a função handleClick chamada pelo manipulador de eventos e não no contexto de uma instùncia da classe Counter , essa função teve acesso aos dados dessa instùncia.

No entanto, essa abordagem tem muitos pontos negativos aos quais esse material Ă© dedicado.

Embora o uso de uma função de seta aqui, é claro, seja uma maneira conveniente de vincular uma função, o comportamento dessa função em muitos aspectos estå longe de ser intuitivo, interferindo no teste e criando problemas em situaçÔes em que, por exemplo, eles tentam usar o objeto correspondente como um protótipo.

Nesses casos, em vez de funçÔes de seta, use funçÔes comuns e, se necessårio, vincule a elas uma instùncia do objeto no construtor:

 class Counter { counter = 0; handleClick() {   this.counter++; } constructor() {   this.handleClick = this.handleClick.bind(this); } } 

ChainsLonga cadeia de chamadas


As funçÔes de seta podem se tornar uma fonte de problemas se forem planejadas para serem usadas em muitas combinaçÔes diferentes, em particular, em longas cadeias de chamadas de função.

A principal razão para esses problemas, como ao usar funçÔes anÎnimas, é que eles fornecem resultados extremamente pouco informativos do rastreamento da pilha de chamadas .

Isso nĂŁo Ă© tĂŁo ruim se, por exemplo, houver apenas um nĂ­vel de aninhamento de chamadas de função, por exemplo, se estivermos falando sobre a função usada no iterador. No entanto, se todas as funçÔes usadas forem declaradas como seta, e essas funçÔes se chamarem, se ocorrer um erro, nĂŁo serĂĄ fĂĄcil descobrir o que estĂĄ acontecendo. As mensagens de erro terĂŁo a seguinte aparĂȘncia:

 {anonymous}() {anonymous}() {anonymous}() {anonymous}() {anonymous}() 

With FunçÔes com contexto dinùmico


A Ășltima das situaçÔes em que estamos discutindo, nas quais as funçÔes de seta podem se tornar uma fonte de problemas, Ă© usĂĄ-las onde vocĂȘ precisa de uma ligação dinĂąmica.

Se funçÔes de seta forem usadas nessas situaçÔes, a dinùmica this ligação não funcionarå. Essa surpresa desagradåvel pode levar a que se confundam as razÔes do que acontece com aqueles que precisam trabalhar com código no qual as funçÔes das setas são usadas incorretamente.

Aqui estão algumas coisas a serem lembradas ao considerar o uso das funçÔes de seta:

  • Manipuladores de eventos sĂŁo chamados com this associado ao atributo de evento currentTarget .
  • Se vocĂȘ ainda estiver usando jQuery, considere que a maioria dos mĂ©todos jQuery vincula this ao elemento DOM selecionado.
  • Se vocĂȘ usa o Vue.js, mĂ©todos e funçÔes calculadas geralmente o vinculam ao componente Vue.

Obviamente, as funçÔes de seta podem ser usadas intencionalmente para alterar o comportamento padrão dos mecanismos de software. Mas, especialmente nos casos com jQuery e Vue, isso geralmente entra em conflito com o funcionamento normal do sistema, o que leva ao fato de que o programador não consegue entender por que algum código que parece completamente normal se recusa a trabalhar repentinamente.

SumĂĄrio


As funçÔes de seta sĂŁo um recurso JavaScript maravilhoso e fresco. Eles permitem, em muitas situaçÔes, escrever cĂłdigo mais conveniente do que antes. Mas, como Ă© o caso de outros recursos, eles tĂȘm vantagens e desvantagens. Portanto, vocĂȘ precisa usar as funçÔes de seta onde elas podem ser Ășteis, sem considerĂĄ-las como um substituto completo para funçÔes comuns.

Caros leitores! VocĂȘ encontrou situaçÔes nas quais o uso das funçÔes de seta leva a erros, inconvenientes ou comportamento inesperado dos programas?

Source: https://habr.com/ru/post/pt428566/


All Articles