Composição de função com função de ordem superior em JavaScript

Dec 04 2022
Neste artigo vamos tentar entender como podemos construir funcionalidades complexas compondo funções menores em JavaScript. COMER, DORMIR, CODIFICAR — Abordagem aninhada Vamos supor que queremos realizar a atividade “COMER, DORMIR, CODIFICAR” e repeti-la novamente.
Foto de Kelly Sikkema no Unsplash

Neste artigo vamos tentar entender como podemos construir funcionalidades complexas compondo funções menores em JavaScript.

COMER, DORMIR, CODIFICAR — Abordagem aninhada

Vamos supor que queremos realizar a atividade “COMER, DORMIR, CODIFICAR” e repeti-la novamente. Aqui está uma abordagem de como poderíamos fazer isso.

const activity = (str) => str.toUpperCase();
const sleep = (str) => `${str} SLEEP`;
const code = (str) => `${str} CODE`;
const repeat = (str) => `${str} | ${str}`;

// EAT SLEEP CODE | EAT SLEEP CODE
console.log(
  repeat(code(sleep(activity('eat'))))
  );

COMER, DORMIR, CODIFICAR — Composição de ordem superior

Veremos como poderíamos melhorar isso usando uma função de ordem superior que criaria uma composição para nós.

const activity = (str) => str.toUpperCase();
const sleep = (str) => `${str} SLEEP`;
const code = (str) => `${str} CODE`;
const repeat = (str) => `${str} | ${str}`;

// Higher order function that accepts any number of functions as arguments
const compose = (...fns) => x => fns.reduce((acc, fn)=> fn(acc),x);
const myRoutine = compose(activity, sleep, code, repeat);

// EAT SLEEP CODE | EAT SLEEP CODE
console.log(myRoutine('eat'));

  • O método compose pode aceitar várias funções como argumentos usando um operador rest.
  • Em seguida, ele retorna uma função que está aguardando seu valor inicial.
  • Dentro desta função retornada, podemos acessar o array de funções que foram passadas como argumento (encerramento).
  • A ordem da função vai da esquerda para a direita. Então usaremos o método de redução, que aceita um acumulador e o valor atual que é uma função. Isso retornará o resultado do valor acumulado na função atual.
  • O segundo argumento para a redução é o nosso valor inicial x.
  • Assim podemos finalmente criar nossa rotina compondo todas as nossas atividades. A rotina deve ser invocada passando o argumento para a primeira função.

Aqui está a exibição detalhada da função de composição para melhor clareza.


// Arrow variant
const compose = (...fns) => x => fns.reduce((acc, fn)=> fn(acc),x);

// Non arrow variant
function compose(...fns) {
  return function (x) {
    return fns.reduce((acc, fn) => fn(acc), x);
  };
}

Essa abordagem tem os benefícios abaixo:

  • Ajuda a reduzir o incômodo causado pelo aninhamento de várias funções.
  • Legível e escalável