Os métodos map, filter e reduce são ferramentas fundamentais da programação funcional em JavaScript. Eles permitem manipular arrays de forma declarativa, evitando loops explícitos e tornando o código mais legível e conciso. Nesta aula, exploraremos cada um deles em profundidade, com exemplos práticos e boas práticas de uso.

Dominar esses métodos é essencial para qualquer desenvolvedor JavaScript, pois eles são amplamente utilizados em frameworks como React, Angular e Vue, além de serem a base para operações com streams de dados. Vamos começar!

Transformação

O método map cria um novo array com os resultados da aplicação de uma função a cada elemento do array original. Ele não modifica o array original, mas retorna um novo array de mesmo tamanho, com os elementos transformados.

A sintaxe é: array.map(callback(elemento, índice, array)). O callback recebe o elemento atual, opcionalmente o índice e o array original. O valor retornado pelo callback é adicionado ao novo array.

Exemplo: dobrar todos os números de um array.

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

Outro exemplo comum: extrair propriedades de objetos.

const usuarios = [
  { nome: 'Ana', idade: 25 },
  { nome: 'João', idade: 30 },
  { nome: 'Maria', idade: 22 }
];
const nomes = usuarios.map(usuario => usuario.nome);
console.log(nomes); // ['Ana', 'João', 'Maria']

O map é ideal para transformações um-para-um, como converter tipos, formatar dados ou aplicar cálculos simples. Lembre-se: sempre retorne um valor no callback, caso contrário o novo array conterá undefined.

Filtragem

O método filter cria um novo array com todos os elementos que passam em um teste implementado pela função callback. Ele retorna um array de tamanho menor ou igual ao original, contendo apenas os elementos que satisfazem a condição.

Sintaxe: array.filter(callback(elemento, índice, array)). O callback deve retornar true para incluir o elemento, ou false para excluí-lo.

Exemplo: filtrar números pares.

const numeros = [1, 2, 3, 4, 5, 6];
const pares = numeros.filter(num => num % 2 === 0);
console.log(pares); // [2, 4, 6]

Exemplo com objetos: filtrar usuários maiores de idade.

const usuarios = [
  { nome: 'Ana', idade: 25 },
  { nome: 'João', idade: 17 },
  { nome: 'Maria', idade: 22 }
];
const maiores = usuarios.filter(usuario => usuario.idade >= 18);
console.log(maiores); // [{ nome: 'Ana', idade: 25 }, { nome: 'Maria', idade: 22 }]

O filter é útil para remover elementos indesejados, buscar dados específicos ou validar condições. Ele não modifica o array original.

Acumulação

O método reduce executa uma função redutora para cada elemento do array, resultando em um único valor de saída. É extremamente versátil e pode ser usado para somar, concatenar, agrupar dados, entre outras operações.

Sintaxe: array.reduce(callback(acumulador, elemento, índice, array), valorInicial). O callback recebe o acumulador (valor retornado na iteração anterior) e o elemento atual. O valor inicial é opcional; se omitido, o primeiro elemento é usado como acumulador e a iteração começa do segundo.

Exemplo: somar todos os números.

const numeros = [1, 2, 3, 4, 5];
const soma = numeros.reduce((acc, num) => acc + num, 0);
console.log(soma); // 15

Exemplo mais complexo: agrupar objetos por uma propriedade.

const pessoas = [
  { nome: 'Ana', time: 'Azul' },
  { nome: 'João', time: 'Vermelho' },
  { nome: 'Maria', time: 'Azul' }
];
const grupos = pessoas.reduce((acc, pessoa) => {
  acc[pessoa.time] = acc[pessoa.time] || [];
  acc[pessoa.time].push(pessoa);
  return acc;
}, {});
console.log(grupos);
// {
//   Azul: [{ nome: 'Ana', time: 'Azul' }, { nome: 'Maria', time: 'Azul' }],
//   Vermelho: [{ nome: 'João', time: 'Vermelho' }]
// }

O reduce é poderoso, mas pode ser menos legível que combinações de map e filter. Use-o quando precisar de uma agregação personalizada ou quando a lógica não puder ser expressa com outros métodos.

Encadeamento

Uma das grandes vantagens de map, filter e reduce é que eles podem ser encadeados, formando pipelines de processamento de dados. Cada método retorna um novo array, permitindo chamar o próximo método diretamente.

Exemplo: dado um array de números, filtrar os pares, dobrá-los e somar o resultado.

const numeros = [1, 2, 3, 4, 5, 6];
const resultado = numeros
  .filter(num => num % 2 === 0)   // [2, 4, 6]
  .map(num => num * 2)            // [4, 8, 12]
  .reduce((acc, num) => acc + num, 0); // 24
console.log(resultado); // 24

Encadeamento com objetos: obter a média de idades de usuários ativos.

const usuarios = [
  { nome: 'Ana', idade: 25, ativo: true },
  { nome: 'João', idade: 17, ativo: false },
  { nome: 'Maria', idade: 22, ativo: true },
  { nome: 'Pedro', idade: 30, ativo: true }
];
const media = usuarios
  .filter(usuario => usuario.ativo)              // apenas ativos
  .map(usuario => usuario.idade)                  // extrair idades
  .reduce((acc, idade, _, arr) => acc + idade / arr.length, 0); // média
console.log(media); // 25.666... (25 + 22 + 30) / 3

Boas práticas: mantenha o encadeamento legível usando quebras de linha e nomes descritivos. Evite encadeamentos muito longos; se necessário, extraia funções nomeadas. Lembre-se de que cada método cria um novo array, o que pode ter impacto em performance com arrays muito grandes, mas para a maioria dos casos é aceitável.

Referências

Exercícios

  1. Dado o array [1, 2, 3, 4, 5], use map para criar um novo array com cada número elevado ao quadrado. Qual é o resultado?

    ✓ Resposta: O resultado é [1, 4, 9, 16, 25]. Código:
    const numeros = [1, 2, 3, 4, 5];
    const quadrados = numeros.map(num => num ** 2);
    console.log(quadrados); // [1, 4, 9, 16, 25]
  2. Dado o array [10, 15, 20, 25, 30], use filter para obter apenas os números maiores que 20. Qual o array resultante?

    ✓ Resposta: O array resultante é [25, 30]. Código:
    const numeros = [10, 15, 20, 25, 30];
    const maiores = numeros.filter(num => num > 20);
    console.log(maiores); // [25, 30]
  3. Use reduce para calcular o produto de todos os números do array [2, 3, 4]. Qual é o resultado?

    ✓ Resposta: O resultado é 24 (2 * 3 * 4). Código:
    const numeros = [2, 3, 4];
    const produto = numeros.reduce((acc, num) => acc * num, 1);
    console.log(produto); // 24
  4. Dado o array de objetos [{nome: 'A', idade: 10}, {nome: 'B', idade: 20}, {nome: 'C', idade: 30}], use encadeamento de filter e map para obter um array com os nomes das pessoas com idade maior ou igual a 20. Qual o resultado?

    ✓ Resposta: O resultado é ['B', 'C']. Código:
    const pessoas = [
      { nome: 'A', idade: 10 },
      { nome: 'B', idade: 20 },
      { nome: 'C', idade: 30 }
    ];
    const nomes = pessoas
      .filter(p => p.idade >= 20)
      .map(p => p.nome);
    console.log(nomes); // ['B', 'C']
  5. Dado o array [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], use filter para obter os ímpares, depois map para multiplicá-los por 3 e finalmente reduce para somar tudo. Qual o valor final?

    ✓ Resposta: O valor final é 75. Ímpares: [1,3,5,7,9]; multiplicados por 3: [3,9,15,21,27]; soma: 75. Código:
    const numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    const resultado = numeros
      .filter(num => num % 2 !== 0)
      .map(num => num * 3)
      .reduce((acc, num) => acc + num, 0);
    console.log(resultado); // 75