As arrow functions, introduzidas no ES6 (ECMAScript 2015), são uma forma mais concisa de escrever funções em JavaScript. Elas oferecem uma sintaxe enxuta e um comportamento diferenciado para o valor de this, o que as torna muito úteis em certos cenários, mas também exige cuidado em outros.

Nesta aula, vamos explorar a sintaxe curta das arrow functions, entender como o this é tratado de forma léxica (baseada no contexto de definição) e aprender quando é melhor optar por funções tradicionais.

Sintaxe curta

A principal característica das arrow functions é sua sintaxe reduzida. Enquanto uma função tradicional usa a palavra-chave function, a arrow function utiliza a seta =>. A forma básica é:

const funcao = (parametros) => { corpo };

Se a função tiver apenas um parâmetro, os parênteses podem ser omitidos:

const quadrado = x => { return x * x; };

Se o corpo da função for uma única expressão, as chaves e a palavra return podem ser omitidas, resultando em um retorno implícito:

const quadrado = x => x * x;

Para funções sem parâmetros ou com dois ou mais parâmetros, os parênteses são obrigatórios:

const saudacao = () => "Olá!";
const soma = (a, b) => a + b;

Quando o corpo da função retorna um objeto literal, é necessário envolvê-lo entre parênteses para evitar ambiguidade com o bloco de código:

const criarPessoa = (nome, idade) => ({ nome: nome, idade: idade });

Diferenças no this

Em funções tradicionais, o valor de this é determinado pelo contexto de chamada (quem invoca a função). Já nas arrow functions, this é herdado do escopo léxico (o escopo onde a função foi definida), ou seja, ele não é redefinido pela chamada.

Isso é particularmente útil em callbacks e métodos de objetos, onde queremos manter o contexto original. Por exemplo:

function Contador() {
  this.valor = 0;
  setInterval(() => {
    this.valor++;
    console.log(this.valor);
  }, 1000);
}
new Contador();

Neste caso, a arrow function dentro de setInterval captura o this do escopo da função Contador, que é a instância do objeto. Se usássemos uma função tradicional, this seria o objeto global (ou undefined em strict mode), causando um erro.

Outro exemplo comum é em métodos de array como map, filter e reduce:

const numeros = [1, 2, 3];
const dobrados = numeros.map(n => n * 2);
console.log(dobrados); // [2, 4, 6]

Aqui, a arrow function é perfeita porque não precisa de seu próprio this.

Quando NÃO usar

Apesar das vantagens, há situações em que arrow functions não são adequadas:

  • Métodos de objetos: Se você usar uma arrow function como método de um objeto, o this não se referirá ao objeto, mas ao escopo externo (geralmente o escopo global ou de uma função pai).
  • Construtores: Arrow functions não podem ser usadas como construtoras com new. Elas não possuem a propriedade prototype e lançam um erro se tentarmos instanciá-las.
  • Métodos que precisam de arguments: Arrow functions não possuem o objeto arguments próprio. Se precisar acessar os argumentos de forma dinâmica, use uma função tradicional ou o operador rest (...args).
  • Event handlers do DOM que precisam de this referindo ao elemento: Em manipuladores de eventos, se você precisa que this seja o elemento alvo, use uma função tradicional. Com arrow function, this será o escopo externo.

Exemplo de erro ao usar arrow function em método de objeto:

const obj = {
  nome: "Exemplo",
  saudacao: () => {
    console.log("Olá, " + this.nome); // this não é obj
  }
};
obj.saudacao(); // "Olá, undefined"

Para esses casos, prefira funções tradicionais:

const obj = {
  nome: "Exemplo",
  saudacao: function() {
    console.log("Olá, " + this.nome);
  }
};
obj.saudacao(); // "Olá, Exemplo"

Boas práticas

  • Use arrow functions para funções curtas e que não precisam de seu próprio this, especialmente em callbacks e métodos de array.
  • Evite arrow functions em métodos de objetos, construtores e funções que usam arguments.
  • Para legibilidade, mantenha a sintaxe consistente: se a função for simples, use a forma concisa; se tiver múltiplas linhas, use chaves e return explícito.

Referências

Exercícios

  1. Converta a função tradicional abaixo em uma arrow function com retorno implícito (uma linha):
    function soma(a, b) {
      return a + b;
    }
  2. ✓ Resposta:
    const soma = (a, b) => a + b;
  3. Escreva uma arrow function que receba um número e retorne seu quadrado, usando retorno implícito.
  4. ✓ Resposta:
    const quadrado = x => x * x;
  5. Explique por que o código a seguir imprime "undefined" e corrija-o usando uma função tradicional:
    const pessoa = {
      nome: "João",
      falar: () => {
        console.log("Meu nome é " + this.nome);
      }
    };
    pessoa.falar();
  6. ✓ Resposta: A arrow function não possui seu próprio this; ele é herdado do escopo global (ou undefined em strict mode). Para corrigir, use uma função tradicional:
    const pessoa = {
      nome: "João",
      falar: function() {
        console.log("Meu nome é " + this.nome);
      }
    };
    pessoa.falar(); // "Meu nome é João"
  7. Dado o array const numeros = [1, 2, 3, 4, 5];, use uma arrow function com filter para obter apenas os números pares.
  8. ✓ Resposta:
    const pares = numeros.filter(n => n % 2 === 0);
    console.log(pares); // [2, 4]
  9. Tente executar new (() => {}) no console do navegador ou Node.js. O que acontece? Por quê?
  10. ✓ Resposta: Acontece um erro: TypeError: (intermediate value) is not a constructor. Isso ocorre porque arrow functions não têm a propriedade prototype e não podem ser usadas como construtoras com new.