Arrow functions são uma sintaxe mais curta para escrever funções em JavaScript, introduzidas no ES6. Elas não apenas tornam o código mais limpo, mas também possuem diferenças importantes em relação ao escopo do this. Nesta aula, vamos explorar como usá-las corretamente e quando evitá-las.

Sintaxe curta

A sintaxe básica de uma arrow function remove a palavra-chave function e usa uma seta (=>) entre os parâmetros e o corpo. Quando há apenas um parâmetro, os parênteses podem ser omitidos; se o corpo for uma única expressão, as chaves e o return também são opcionais.

// Função tradicional
function soma(a, b) {
  return a + b;
}

// Arrow function equivalente
const soma = (a, b) => a + b;

// Com um único parâmetro, sem parênteses
const quadrado = x => x * x;

// Sem parâmetros, parênteses vazios obrigatórios
const saudacao = () => 'Olá!';

Para múltiplas linhas ou instruções, é necessário usar chaves e return explícito:

const processar = (a, b) => {
  const resultado = a * b;
  console.log('Resultado:', resultado);
  return resultado;
};

Diferenças no this

Em funções tradicionais, o valor de this depende de como a função é chamada (contexto de execução). Arrow functions, porém, não possuem seu próprio this; elas capturam o this do escopo léxico (onde foram definidas). Isso resolve muitos problemas comuns, especialmente em callbacks e métodos de objetos.

const obj = {
  nome: 'Exemplo',
  funcaoTradicional: function() {
    console.log(this.nome); // 'Exemplo'
  },
  arrowFunction: () => {
    console.log(this.nome); // undefined (this global)
  }
};

obj.funcaoTradicional(); // 'Exemplo'
obj.arrowFunction(); // undefined

No exemplo acima, a arrow function não tem seu próprio this, então herda o this do escopo global (ou do módulo). Isso é útil em situações como eventos ou temporizadores, onde queremos preservar o contexto externo:

function Botao() {
  this.clicado = false;
  document.querySelector('button').addEventListener('click', () => {
    this.clicado = true; // this refere-se à instância de Botao
  });
}

Quando NÃO usar

Apesar das vantagens, arrow functions não são adequadas em todos os cenários. Evite usá-las nos seguintes casos:

  • Métodos de objeto: Se você precisa acessar o this do objeto, use função tradicional.
  • Construtores: Arrow functions não podem ser usadas com new (lançam erro).
  • Manipulação de arguments: Arrow functions não possuem o objeto arguments; use rest parameters (...args).
  • Métodos que precisam de prototype: Arrow functions não têm prototype, portanto não podem ser usadas como construtores.
// Exemplo de erro com construtor
const Construtor = () => {};
const obj = new Construtor(); // TypeError: Construtor is not a constructor

// Uso de rest parameters em vez de arguments
const funcao = (...args) => {
  console.log(args); // array com os argumentos
};

Boas práticas

Prefira arrow functions para funções curtas e callbacks, especialmente quando o this deve vir do escopo pai. Para funções mais complexas ou que dependem do contexto dinâmico, use funções tradicionais. Sempre considere a legibilidade do código.

Referências

Exercícios

  1. Converta a função tradicional abaixo em uma arrow function de uma linha:
    function dobro(x) {
      return x * 2;
    }

    ✓ Resposta:
    const dobro = x => x * 2;
  2. O que será impresso no console?
    const obj = {
      valor: 10,
      metodo: () => {
        console.log(this.valor);
      }
    };
    obj.metodo();

    ✓ Resposta: undefined, porque arrow functions capturam o this do escopo externo (global), não do objeto.
  3. Crie uma arrow function que receba dois números e retorne o maior deles. Use uma única expressão.

    ✓ Resposta:
    const maior = (a, b) => a > b ? a : b;
  4. Por que o código abaixo lança um erro?
    const Carro = () => {
      this.marca = 'Ford';
    };
    const fusca = new Carro();

    ✓ Resposta: Arrow functions não podem ser usadas como construtores. O uso de new com uma arrow function lança TypeError: Carro is not a constructor.
  5. Reescreva a função abaixo usando arrow function e rest parameters para capturar todos os argumentos:
    function lista() {
      return Array.from(arguments).join(', ');
    }

    ✓ Resposta:
    const lista = (...args) => args.join(', ');