Skip to content

Currying – Aplicação Parcial de Função JavaScript

Esse é o segundo post da série sobre aplicação de função JavaScript. Leia a primeira parte Aplicação de Funções JavaScript – Parte 01

Agora que você já leu o primeiro artigo sobre aplicação de função e já está entendendo como funciona, vamos avançar um pouco e trabalhar com currying.

Currying – ou aplicação parcial de função – é uma técnica que nos permite reduzir uma determinada função com vários argumentos para uma sequência de funções de apenas um argumento. Isso é uma característica da programação funcional.

Veja um exemplo, dado que temos uma função que soma dois números:

const soma = (x, y) => x + y; 

Aplicando o currying, ela ficaria dessa forma:

const somaCurrying = x => y => x + y; 

A primeira impressão faz parecer que tal abordagem só faz complicar a lógica aplicada, mas isso nos dá uma grande vantagem: reutilização de código.

Na primeira função, temos que passar sempre 2 argumentos. Mas e se precisassemos de uma função que somasse um número pré-definido com outro variável? É aí que tiramos proveito dessa abordagem:

Por exemplo:

const somaDez = somaCurrying(10);
const somaVinte = somaCurrying(20);
somaDez(5) // Saída 15
somaVinte(10) // Saída 30

Ou seja, quando definimos as funções somaDez e somaVinte, nós recebemos da função somaCurrying não o resultado de x + y, mas sim uma função que recebe y como argumento, porém, com o valor de x já previamente definido no contexto da função somaCurrying.

A função somaCurrying retornará o resultado, apenas se for feita uma invocação imediata da função retornada, por exemplo:

somaCurrying(10)(30); //Saída -> 40

Utilizando call() e apply() no currying

No exemplo anterior, a função somaCurrying possui um papel explícito que é o de somar dois números. Mas e se quisessemos generalizar a nossa função para que, independente do seu propósito, aceite parâmetros parciais?

Vejamos um exemplo:

const genericFunction = function(fn) {
    const args = Array.prototype.slice.call(arguments, 1);
    return function() {
       return fn.apply(null, 
              args.concat(Array.prototype.slice.call(arguments)))
    }
}

Meio confuso, não? Então vamos por partes…

  • Temos uma função chamada genericFunction que recebe uma outra função como argumento. Embora genericFunction tenha sido declarada recebendo apenas um argumento, o JavaScript nos permite passar uma quantidade diferente de argumentos declarados em uma função e é através do objeto arguments que conseguimos acessar esses argumentos adicionais.
  • Dentro de genericFunction o objeto arguments é transformado em um array através do método slice(), armazenado na constante args e é retornada uma função que retorna a execução da função fn aplicada com o método apply(), onde o primeiro argumento aponta pra null e o segundo argumento é o array de args do contexto de genericFunction concatenado com os argumentos adicionais vindos da função retornada por genericFunction.

Vejamos a execução:

const sum = genericFunction((x, y) => x + y, 10);
sum(10); //Saída -> 20

sum recebe uma função anônima que retorna a execução da função anônima passada como primeiro argumento para a genericFunction e o valor 10 passado como 2º argumento é acessado através do objeto arguments e armazenado no array args.
Quando sum é invocada a função que foi passada como primeiro argumento para genericFunction é aplicada e tem seu this como null e recebe como argumento o array args de genericFunction concatenado com o array de argumentos recebidos por sum.

Bom, por hoje é só!

Até a próxima!

Published inArtigosJavaScript