Nas aulas anteriores, aprendemos a:

  • Preservar estado com closures
  • Evitar efeitos colaterais com imutabilidade
  • Especializar funções com currying

Agora vamos juntar tudo isso em um único conceito poderoso:

Composição de Funções.

🎯 Objetivo da aula

Ao final desta aula, você será capaz de:

  • Entender o que é composição de funções
  • Encadear funções pequenas para resolver problemas maiores
  • Escrever código mais legível e previsível
  • Reconhecer composição em código real
  • Combinar composição com currying e imutabilidade

O que é composição de funções?

Composição de funções é a ideia de:

combinar funções pequenas para formar uma função maior.

Cada função faz uma única coisa — e faz bem.

Exemplo sem composição (procedural)

Veja um código comum:

 
  function processarTexto(texto) 
  { 
    const maiusculo = texto.toUpperCase(); 
    const semEspacos = maiusculo.trim(); 
    const comPrefixo = "Resultado: " + semEspacos;
    return comPrefixo;
  }
  console.log(processarTexto(" olá mundo "));
  // Saída será: Resultado: OLÁ MUNDO

Funciona, mas:

  • Tudo está misturado
  • Dificulta reutilização
  • Dificulta testes

O mesmo problema com funções pequenas

 
  const paraMaiusculo = texto => texto.toUpperCase(); 
  const removerEspacos = texto => texto.trim(); 
  const adicionarPrefixo = texto => "Resultado: " + texto; 

Agora temos peças reutilizáveis.

Compondo funções manualmente

 
  const resultado = adicionarPrefixo( removerEspacos( paraMaiusculo(" olá mundo ") ) );
  console.log(resultado);
  // Saída será: Resultado: OLÁ MUNDO

Isso já é composição.

Criando uma função compose

Vamos automatizar essa ideia:

 
  function compose(...funcoes) 
  { 
    return function (valorInicial) 
    { 
      return funcoes.reduceRight((valor, funcao) => 
      { 
        return funcao(valor); 
      }, valorInicial); 
    }; 
  } 

Agora vamos analisar com calma a função acima, que costuma causar estranhamento à primeira vista, mas que na verdade apenas formaliza a ideia de composição de funções.

Não se preocupe em entender tudo de uma vez. Vamos desmontar essa função peça por peça.

A função inteira (vamos olhar ela “aberta”)

 function compose(...funcoes) {
return function (valorInicial) {
return funcoes.reduceRight((valor, funcao) => {
return funcao(valor);
}, valorInicial);
};
}

Antes de entrar nos detalhes, guarde esta ideia:

compose não executa nada imediatamente. Ela monta uma nova função.

1️⃣ O que é ...funcoes?

O operador ... é o rest operator.

Ele permite que a função receba um número indefinido de argumentos e os agrupe em um array.

Ou seja, ao chamar:

 compose(f1, f2, f3); 

Internamente, teremos:

 funcoes === [f1, f2, f3] 

Cada item do array é uma função que será aplicada na composição.

2️⃣ Por que compose retorna outra função?

Observe esta parte:

 return function (valorInicial) { ... } 

Isso acontece porque a composição é feita em duas etapas:

  • Primeiro, informamos quais funções serão usadas
  • Depois, informamos o valor que será processado

Exemplo:

 const processar = compose(f1, f2, f3); processar("olá"); 

Aqui temos currying e closure trabalhando juntos:

  • As funções ficam “guardadas”
  • A função retornada lembra delas

3️⃣ O papel de valorInicial

O parâmetro valorInicial representa o dado que será transformado.

Esse valor será passado por todas as funções, uma após a outra.

Mentalmente, o fluxo é este:

 valor → f3 → f2 → f1 

4️⃣ O coração da função: reduceRight

Agora vamos analisar a parte mais importante:

 funcoes.reduceRight((valor, funcao) => { return funcao(valor); }, valorInicial); 

É aqui que a composição realmente acontece.

5️⃣ O que é reduceRight?

O método reduceRight percorre um array da direita para a esquerda.

Se tivermos:

 funcoes = [f1, f2, f3] 

A ordem de execução será:

 f3 → f2 → f1 

Isso corresponde exatamente à composição matemática:

 f1(f2(f3(valor))) 

6️⃣ O acumulador (valor)

No reduceRight, o parâmetro valor é o acumulador.

Ele começa com o valorInicial e, a cada passo:

  • recebe o resultado da função anterior
  • é passado para a próxima função

O fluxo real fica assim:

 valorInicial ↓ f3(valorInicial) ↓ f2(resultado) ↓ f1(resultado) 

7️⃣ Execução passo a passo (exemplo real)


   const paraMaiusculo = x => x.toUpperCase(); 
   const removerEspacos = x => x.trim(); 
   const adicionarPrefixo = x => "Resultado: " + x;
   const processar = compose(adicionarPrefixo, removerEspacos, paraMaiusculo);
   processar(" olá ");

Internamente, a lista de funções será:

 [adicionarPrefixo, removerEspacos, paraMaiusculo] 

A execução acontece assim:

  • Primeiro: paraMaiusculo → " OLÁ "
  • Depois: removerEspacos → "OLÁ"
  • Por fim: adicionarPrefixo → "Resultado: OLÁ"

8️⃣ Por que não usar reduce?

O método reduce percorre o array da esquerda para a direita.

Isso resultaria em:

 f3(f2(f1(valor))) 

Ou seja, a ordem ficaria invertida.

Por isso, usamos reduceRight para manter a composição correta.

9️⃣ Traduzindo a função para “português”

Podemos traduzir a função compose assim:

Receba várias funções. Crie uma nova função. Quando essa nova função receber um valor, aplique as funções da última para a primeira, passando o resultado de uma para a outra.

Essa é a essência da composição de funções.

Usando compose

 
  const processarTexto = compose(adicionarPrefixo, removerEspacos, paraMaiusculo);
  console.log(processarTexto(" olá mundo "));
  // Saída será: Resultado: OLÁ MUNDO

Agora o fluxo fica:

  • claro
  • linear
  • declarativo

Composição funciona melhor com funções puras

Funções puras:

  • não alteram dados externos
  • não dependem de estado externo
  • sempre retornam o mesmo resultado
Imutabilidade + funções puras = composição previsível.

Composição + Currying

Currying cria funções de um argumento — ideais para composição.


  const paraMaiusculo = texto => texto.toUpperCase();
  function compose(...funcoes) 
  { 
    return function (valorInicial) 
    { 
      return funcoes.reduceRight((valor, funcao) => 
      { 
        return funcao(valor); 
      }, valorInicial); 
    }; 
  } 
  const adicionarSufixo = sufixo => texto => texto + sufixo;
  const comExclamacao = adicionarSufixo("!");
  const gritar = compose(comExclamacao, paraMaiusculo);
  console.log(gritar("olá"));
  // Saída será: OLÁ!

Por que isso é poderoso?

Porque agora você:

  • pensa em fluxo de dados
  • não mistura responsabilidades
  • cria código testável
  • reutiliza comportamento
Isso é base de: programação funcional pipelines de dados bibliotecas modernas

Quando não exagerar

Composição:

  • não substitui código simples
  • não deve ser usada só por estilo
Clareza vem antes de elegância.

Resumo da aula para nunca mais esquecer

  • Composição combina funções pequenas
  • Cada função faz uma única coisa
  • Imutabilidade garante previsibilidade
  • Currying facilita composição
  • Código fica mais claro e reutilizável

Na próxima etapa, entramos oficialmente no módulo avançado final, aplicando esses conceitos em arquiteturas reais e projetos mais complexos.


HARDWARE

Entendendo o seu computador

O que há dentro do meu computador?

Existem alguns componentes fundamentais presentes dentro do seu computador e é muito importante que você conheça um pouco sobre eles, seja para argumentar com algum vendedor durante a compra de um novo PC ou para identificar alguma atitude desleal de algum técnico que esteja te passando um orçamento para reparo. Na seção Raio-X aqui do Contém Bits você pode conhecer e entender mais detalhadamente sobre cada componente, ou também pode clicar abaixo no componente que deseja, para conhecê-lo melhor.

  • Gabinetes

  • Placas-Mãe

  • Processadores

  • Memória

  • Fontes

  • Drives Ópticos

  • Discos Rígidos

  • SSD

  • Placas de Som

  • Placas de Vídeo

Você Sabia?

O título Space Invaders, lançado em 1980, fez tanto sucesso em todo o mundo que as pessoas compravam o console Atari apenas para poderem jogá-lo em casa. Saiba mais sobre este incrível título clicando aqui.


Desde o seu lançamento, em 1985, o fantástico jogo Tetris vende pelo menos 70 milhões de unidades por ano em todo o mundo! Os dados são oficiais e fornecidos pela THQ, uma das distribuidoras do título.


Street Fighter 2, lançado para o Super Nintendo no início dos anos 90, foi o principal responsável pelo aumento nas vendas deste console. Graças ao sucesso do título nos Arcades e à perfeita adaptação ao console, muitos consumidores adquiriram o SNES para jogarem o título em casa. Saiba mais.


Instalar vários aplicativos com o mesmo propósito, como editores de texto, reprodutores de músicas ou vídeos e até programas antívirus sobrecarregam o seu sistema operacional e ainda ocupam espaço desnecessário em seu HD. Tenha apenas um bom programa para cada função.


A empresa Universal City Studios, detentora dos direitos autorais do King Kong, processou a Nintendo logo após o lançamento de Donkey Kong, pois segundo ela, o game violava os seus direitos. Ela venceu o processo e recebeu da Nintendo uma indenização de quase 2 milhões de dólares.