O que são Higher-Order Functions?
Higher-Order Functions (HOF) são funções que recebem outras funções como argumentos ou retornam funções como resultado. Elas são fundamentais na programação funcional e permitem escrever código mais reutilizável, expressivo e modular. Em JavaScript, como tudo é um objeto — inclusive funções — trabalhar com HOF é natural e poderoso.
O grande benefício é a abstração: em vez de escrever loops repetitivos, você descreve o que quer fazer com seus dados. Isso torna o código mais legível e menos propenso a erros. Vamos explorar as três HOFs mais importantes: map, filter e reduce.
Map, Filter e Reduce na Prática
Map: Transformar Dados
Map aplica uma função a cada elemento de um array e retorna um novo array com os resultados. Use-o quando quiser transformar todos os itens de forma igual.
const numeros = [1, 2, 3, 4, 5];
const dobrados = numeros.map(n => n * 2);
console.log(dobrados); // [2, 4, 6, 8, 10]
// Exemplo real: converter objetos de uma API
const usuarios = [
{ id: 1, nome: "Ana" },
{ id: 2, nome: "Bruno" }
];
const nomes = usuarios.map(u => u.nome);
console.log(nomes); // ["Ana", "Bruno"]
Filter: Selecionar Dados
Filter cria um novo array contendo apenas os elementos que passam em um teste. Use-o para remover ou selecionar itens baseado em uma condição.
const numeros = [1, 2, 3, 4, 5, 6];
const pares = numeros.filter(n => n % 2 === 0);
console.log(pares); // [2, 4, 6]
// Exemplo real: listar apenas usuários ativos
const usuarios = [
{ id: 1, nome: "Ana", ativo: true },
{ id: 2, nome: "Bruno", ativo: false },
{ id: 3, nome: "Carlos", ativo: true }
];
const ativos = usuarios.filter(u => u.ativo);
console.log(ativos); // Ana e Carlos
Reduce: Agregar Dados
Reduce acumula valores em um único resultado, passando por cada elemento. Use-o para sumarizar dados: somas, contagens, agregações ou transformações complexas.
const numeros = [1, 2, 3, 4, 5];
const soma = numeros.reduce((acumulador, atual) => acumulador + atual, 0);
console.log(soma); // 15
// Exemplo real: contar ocorrências de palavras
const palavras = ["gato", "cão", "gato", "pato", "cão", "cão"];
const contagem = palavras.reduce((acc, palavra) => {
acc[palavra] = (acc[palavra] || 0) + 1;
return acc;
}, {});
console.log(contagem); // { gato: 2, cão: 3, pato: 1 }
Composição de Higher-Order Functions
Composição é combinar múltiplas funções pequenas para resolver problemas complexos. A beleza é que map, filter e reduce retornam arrays (ou valores), permitindo encadeamento natural.
const usuarios = [
{ id: 1, nome: "Ana", salario: 3000, ativo: true },
{ id: 2, nome: "Bruno", salario: 2500, ativo: false },
{ id: 3, nome: "Carlos", salario: 4000, ativo: true }
];
// Problema: somar salários apenas de usuários ativos
const totalAtivos = usuarios
.filter(u => u.ativo)
.map(u => u.salario)
.reduce((acc, sal) => acc + sal, 0);
console.log(totalAtivos); // 7000 (Ana + Carlos)
Esse padrão é extremamente legível: filtro → extraio salários → somo. Para problemas ainda mais complexos, crie funções compostas reutilizáveis:
// Criar predicados e transformadores reutilizáveis
const ehAtivo = u => u.ativo;
const extrairSalario = u => u.salario;
const somar = (acc, val) => acc + val;
// Aplicar em qualquer contexto
const totalAtivos = usuarios
.filter(ehAtivo)
.map(extrairSalario)
.reduce(somar, 0);
// Outra composição: média salarial
const quantidadeAtivos = usuarios.filter(ehAtivo).length;
const mediaAtivos = totalAtivos / quantidadeAtivos;
console.log(mediaAtivos); // 3500
Criando Funções Compostas Avançadas
Função Compose Genérica
Uma função compose recebe múltiplas funções e as aplica em sequência. Isso é programação funcional pura:
// Compose: aplica funções da direita para esquerda
const compose = (...funcs) => valor =>
funcs.reduceRight((acc, func) => func(acc), valor);
// Funções básicas
const adicionar10 = x => x + 10;
const multiplicarPor2 = x => x * 2;
const dividirPor5 = x => x / 5;
// Compor: (((5 * 2) + 10) / 5)
const pipeline = compose(dividirPor5, adicionar10, multiplicarPor2);
console.log(pipeline(5)); // 4
// Pipe: aplica da esquerda para direita (mais intuitivo)
const pipe = (...funcs) => valor =>
funcs.reduce((acc, func) => func(acc), valor);
const processamento = pipe(multiplicarPor2, adicionar10, dividirPor5);
console.log(processamento(5)); // 4
Exemplo Real: Processamento de Dados
const dados = [
{ nome: "Alice", idade: 25, ativo: true },
{ nome: "Bob", idade: 17, ativo: false },
{ nome: "Carol", idade: 30, ativo: true }
];
// Predicados e transformadores específicos
const maioresDeIdade = p => p.idade >= 18;
const ehAtivo = p => p.ativo;
const extrairNome = p => p.nome;
// Composição prática
const nomesMaioresEAtivos = dados
.filter(maioresDeIdade)
.filter(ehAtivo)
.map(extrairNome);
console.log(nomesMaioresEAtivos); // ["Alice", "Carol"]
// Ou com um único filter (otimizado):
const nomesMaioresEAtivos2 = dados
.filter(p => maioresDeIdade(p) && ehAtivo(p))
.map(extrairNome);
Conclusão
Higher-Order Functions são pilares da programação moderna em JavaScript. Ao dominar map para transformações, filter para seleções e reduce para agregações, você escreve código declarativo e robusto. Composição de HOFs permite resolver problemas complexos de forma elegante e legível — é o caminho para se tornar um desenvolvedor mais eficiente. Pratique combinando essas funções em seus projetos reais e perceba como seu código fica mais profissional e manutenível.