Programação Funcional em JavaScript: da Teoria à Prática
Programação Funcional (PF) é um paradigma que trata a computação como a avaliação de funções matemáticas e evita a mudança de estado e dados mutáveis. No JavaScript moderno, especialmente no ambiente Node.js, a abordagem funcional está se tornando cada vez mais popular devido à sua previsibilidade, testabilidade e modularidade. Neste artigo, vamos analisar os conceitos-chave da PF e mostrar como aplicá-los em projetos reais.
1. Funções Puras e Ausência de Efeitos Colaterais
Uma função pura é uma função que:
- Sempre retorna o mesmo resultado para os mesmos argumentos (determinismo).
- Não causa efeitos colaterais (não altera variáveis externas, não exibe dados, não acessa o sistema de arquivos).
Exemplo de função pura:
// Função pura: soma dois númerosconst add = (a, b) => a + b;
console.log(add(2, 3)); // 5console.log(add(2, 3)); // 5 — sempre igualExemplo de função impura:
let counter = 0;const increment = () => { counter++; // Efeito colateral: altera variável externa return counter;};
console.log(increment()); // 1console.log(increment()); // 2 — resultado diferenteNa programação funcional, nos esforçamos para escrever apenas funções puras. Isso torna o código mais fácil de testar e depurar.
2. Imutabilidade de Dados
Imutabilidade significa que os dados não são alterados após a criação. Em vez de modificar um objeto existente, criamos uma nova cópia dele com as alterações necessárias. Em JavaScript, para isso, frequentemente usamos o operador spread (...) ou o método Object.assign.
Exemplo de atualização imutável de objeto:
const user = { name: 'Alice', age: 30 };
// Ruim: mutaçãouser.age = 31;
// Bom: criamos um novo objetoconst updatedUser = { ...user, age: 31 };
console.log(user); // { name: 'Alice', age: 30 }console.log(updatedUser); // { name: 'Alice', age: 31 }Para arrays, também usamos métodos imutáveis:
const numbers = [1, 2, 3];
// Mutação (ruim)numbers.push(4);
// Imutável (bom)const newNumbers = [...numbers, 4];
console.log(numbers); // [1, 2, 3]console.log(newNumbers); // [1, 2, 3, 4]3. Funções de Alta Ordem: map, filter, reduce
Funções de alta ordem são funções que recebem outras funções como argumentos ou as retornam. Os três métodos mais populares em JavaScript são map, filter e reduce. Eles permitem processar arrays sem loops e mutações.
3.1. map() — Transformação de Array
O método map cria um novo array, aplicando uma função a cada elemento do array original.
const prices = [100, 200, 300];const withTax = prices.map(price => price * 1.2);
console.log(withTax); // [120, 240, 360]// O array original não foi alteradoconsole.log(prices); // [100, 200, 300]3.2. filter() — Filtragem de Array
O método filter retorna um novo array contendo apenas os elementos para os quais a função passada retornou true.
const ages = [15, 22, 18, 30, 12];const adults = ages.filter(age => age >= 18);
console.log(adults); // [22, 18, 30]3.3. reduce() — Agregação de Dados
O método reduce reduz um array a um único valor (número, objeto, string).
const numbers = [1, 2, 3, 4, 5];const sum = numbers.reduce((accumulator, current) => accumulator + current, 0);
console.log(sum); // 15Combinando esses métodos, podemos resolver problemas complexos de forma funcional:
const users = [ // ... continuação do código