<h2>Imutabilidade: O Fundamento da Programação Funcional</h2>
<p>A imutabilidade é o pilar central da programação funcional. Significa que, uma vez criado, um objeto ou dado nunca deve ser modificado. Em vez de alterar dados existentes, criamos novas versões deles. Isso elimina efeitos colaterais inesperados e torna o código mais previsível e testável.</p>
<p>No JavaScript, a imutabilidade não é forçada nativamente, mas podemos implementá-la através de boas práticas. Observe:</p>
<pre><code class="language-javascript"></code></pre>
<p>O spread operator (<code>...</code>) e <code>Object.assign()</code> são aliados poderosos. Para arrays, usamos métodos que retornam novos arrays:</p>
<pre><code class="language-javascript"></code></pre>
<h2>Funções Puras: Previsibilidade e Testabilidade</h2>
<p>Uma função pura é aquela que, dado um mesmo input, sempre produz o mesmo output, sem depender de estado externo ou causar efeitos colaterais. Ela não modifica variáveis globais, não realiza I/O e não altera seus parâmetros.</p>
<p>Funções puras são a essência do código funcional. Veja a diferença:</p>
<pre><code class="language-javascript"></code></pre>
<p>Funções puras são imediatamente testáveis:</p>
<pre><code class="language-javascript">function aplicarDesconto(preco, percentual) {
return preco * (1 - percentual / 100);
}
console.log(aplicarDesconto(100, 10)); // 90
console.log(aplicarDesconto(100, 10)); // 90 - determinístico!
// Fácil de testar
const resultado = aplicarDesconto(200, 20);
console.assert(resultado === 160, 'Desconto incorreto');</code></pre>
<p>Um exemplo mais prático com arrays:</p>
<pre><code class="language-javascript"></code></pre>
<h2>Composição: Construindo Poder com Simplicidade</h2>
<p>A composição funcional consiste em criar funções pequenas e focadas, depois combiná-las para resolver problemas complexos. Cada função faz uma coisa bem feita, e as conectamos como peças de um quebra-cabeça.</p>
<h3>Composição Básica</h3>
<pre><code class="language-javascript">// Funções simples e puras
const multiplicarPor2 = n => n * 2;
const somar5 = n => n + 5;
const converter = n => Resultado: ${n};
// Composição manual (de dentro para fora)
const valor = 10;
const resultado = converter(somar5(multiplicarPor2(valor)));
console.log(resultado); // "Resultado: 25"</code></pre>
<h3>Função de Composição (Composer)</h3>
<p>Para evitar o aninhamento excessivo, criamos uma função que compõe outras:</p>
<pre><code class="language-javascript">// Função auxiliar para compor
const compose = (...funcoes) => valor =>
funcoes.reduceRight((acc, fn) => fn(acc), valor);
const multiplicarPor2 = n => n * 2;
const somar5 = n => n + 5;
const converter = n => Resultado: ${n};
const pipeline = compose(converter, somar5, multiplicarPor2);
console.log(pipeline(10)); // "Resultado: 25"</code></pre>
<h3>Pipe: Composição da Esquerda para Direita</h3>
<p>Às vezes é mais intuitivo ler de esquerda para direita:</p>
<pre><code class="language-javascript">const pipe = (...funcoes) => valor =>
funcoes.reduce((acc, fn) => fn(acc), valor);
const multiplicarPor2 = n => n * 2;
const somar5 = n => n + 5;
const converter = n => Resultado: ${n};
const pipeline = pipe(multiplicarPor2, somar5, converter);
console.log(pipeline(10)); // "Resultado: 25"</code></pre>
<h3>Exemplo Prático: Processamento de Dados</h3>
<pre><code class="language-javascript">// Funções simples
const buscarUsuarios = () => [
{ id: 1, nome: 'Ana', idade: 25, ativo: true },
{ id: 2, nome: 'Bruno', idade: 30, ativo: false },
{ id: 3, nome: 'Carlos', idade: 28, ativo: true }
];
const apenasAtivos = usuarios => usuarios.filter(u => u.ativo);
const maioresQue26 = usuarios => usuarios.filter(u => u.idade > 26);
const obterNomes = usuarios => usuarios.map(u => u.nome);
// Composição
const pipe = (...fns) => v => fns.reduce((acc, fn) => fn(acc), v);
const obterNomesValidos = pipe(
buscarUsuarios,
apenasAtivos,
maioresQue26,
obterNomes
);
console.log(obterNomesValidos()); // ['Carlos']</code></pre>
<h2>Conclusão</h2>
<p>Três pilares transformam seu código em JavaScript funcional: <strong>Imutabilidade</strong> garante que dados não sejam alterados inesperadamente, reduzindo bugs. <strong>Funções puras</strong> tornam o código determinístico e testável, pois sempre produzem o mesmo resultado para o mesmo input. <strong>Composição</strong> permite construir soluções complexas juntando funções pequenas, focadas e reutilizáveis.</p>
<p>Esses conceitos não são apenas teóricos — melhoram a qualidade real do seu código, facilitam testes automatizados e tornam manutenção mais segura. Comece pequeno: escreva funções puras, evite mutações com spread operators e componha suas soluções. Com prática, a programação funcional se tornará sua segunda natureza.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Glossary/Functional_programming" target="_blank" rel="noopener noreferrer">MDN Web Docs - Functional Programming</a></li>
<li><a href="https://javascript.info/closure" target="_blank" rel="noopener noreferrer">JavaScript.info - Closures e Functional Programming</a></li>
<li><a href="https://medium.com/javascript-scene/composing-software-the-book-f31c77fc3ddc" target="_blank" rel="noopener noreferrer">Medium - Functional Programming in JavaScript</a></li>
<li><a href="https://frontendmasters.com/courses/functional-javascript/" target="_blank" rel="noopener noreferrer">Frontend Masters - Composing Software</a></li>
<li><a href="https://eloquentjavascript.net/05_higher_order.html" target="_blank" rel="noopener noreferrer">Eloquent JavaScript - Capítulo sobre Funções de Ordem Superior</a></li>
</ul>