W3docs

Currying e Aplicação Parcial em JavaScript

Currying e aplicação parcial são técnicas poderosas de programação funcional que melhoram a modularidade e a reutilização do seu código JavaScript.

Currying e aplicação parcial são técnicas poderosas de programação funcional que podem melhorar significativamente a modularidade e a reutilização do seu código JavaScript. Ambas dependem de closures — a capacidade de uma função interna de lembrar as variáveis da função externa que a criou — de modo que uma função retornada mantém os argumentos que você já forneceu.

Este artigo aborda o que é currying e por que ele é importante, como escrever um helper curry reutilizável, como a aplicação parcial difere do currying, casos de uso reais e as boas práticas (e armadilhas) a ter em mente.

Entendendo o Currying

Currying é uma técnica em que uma função é transformada em uma sequência de funções, cada uma recebendo um único argumento. Ele permite que você decomponha uma função que recebe vários argumentos em uma série de funções unárias (de argumento único).

Exemplo de Currying

Considere uma função simples que soma três números:

function add(a, b, c) {
    return a + b + c;
}

Podemos transformar essa função em uma versão com currying:

javascript— editable

Explicação:

  • A função add recebe três argumentos e retorna a soma deles.
  • A função curryAdd é uma versão com currying de add. Ela recebe um argumento a e retorna outra função que recebe b. Essa segunda função retorna mais uma função que recebe c. A função mais interna retorna a soma de a, b e c.

Benefícios do Currying

  1. Reutilização: Funções com currying permitem criar novas funções fixando alguns argumentos. Isso melhora a reutilização ao permitir criar facilmente versões especializadas de uma função sem duplicar código.
javascript— editable

Aqui, curriedAdd é uma versão com currying da função add. Ela nos permite criar funções especializadas como add5 fixando o primeiro argumento (a) em 5. Isso promove a reutilização de código, pois podemos criar várias funções especializadas sem repetir a lógica de adição.

  1. Composição de Funções: O currying facilita a composição de funções. Composição de funções é o processo de combinar duas ou mais funções para produzir uma nova função.
javascript— editable

Neste exemplo, composemos as funções multiply e addOne usando currying. A forma concisa a => b => a * b depende de arrow functions, que tornam funções aninhadas de argumento único fáceis de ler. Ao aplicar currying nessas funções, podemos criar facilmente uma nova função addOneThenMultiplyBy5, que primeiro adiciona 1 à entrada (x) e depois multiplica o resultado por 5. Isso demonstra como o currying facilita a composição de funções, tornando mais simples criar novas funções combinando as existentes.

Implementando Currying em JavaScript

Podemos criar uma função utilitária para aplicar currying a qualquer função. Aqui está uma implementação de uma função de currying genérica:

javascript— editable

Explicação:

  1. Função de Currying (curry):

    • A função curry recebe outra função fn como entrada.
    • Ela retorna uma nova função chamada curried.
    • Essa função curried aceita qualquer número de argumentos usando a sintaxe de parâmetro rest (...args).
  2. Função com Currying (curried):

    • Dentro de curried, verifica-se se o número de argumentos fornecidos (args.length) é maior ou igual ao número de argumentos esperados pela função original fn (fn.length).
    • Se forem fornecidos argumentos suficientes, a função original fn é chamada com esses argumentos usando fn.apply(this, args).
    • Se não forem fornecidos argumentos suficientes, é retornada uma nova função que aceita mais argumentos (nextArgs) usando o operador spread (...nextArgs).
    • Essa nova função chama curried recursivamente com os argumentos combinados (args.concat(nextArgs)), garantindo que todos os argumentos sejam eventualmente coletados antes de chamar a função original fn.

    Nota: fn.length conta apenas parâmetros sem valores padrão e ignora parâmetros rest.

  3. Exemplo de Uso:

    • Definimos uma função multiply que recebe três argumentos e retorna o produto deles.
    • Criamos uma versão com currying da função multiply passando-a para a função curry, que retorna uma nova função curriedMultiply.
    • Agora, curriedMultiply pode ser chamada com um, dois ou três argumentos.
    • Cada vez que chamamos curriedMultiply com um ou mais argumentos, ela retorna uma nova função até que todos os argumentos sejam coletados, momento em que retorna o resultado da multiplicação dos argumentos.

Explorando a Aplicação Parcial

Aplicação parcial é uma técnica em que você cria uma nova função pré-preenchendo alguns argumentos da função original. Isso é especialmente útil para criar funções especializadas.

Exemplo de Aplicação Parcial

Considere a seguinte função que formata uma mensagem:

function formatMessage(greeting, name) {
    return `${greeting}, ${name}!`;
}

Podemos criar uma função com aplicação parcial:

javascript— editable

Explicação:

  • A função formatMessage recebe dois argumentos, greeting e name, e retorna uma mensagem formatada.
  • A função partial recebe uma função fn e alguns argumentos predefinidos (...presetArgs). Ela retorna uma nova função que recebe os argumentos restantes (...laterArgs).
  • Quando a nova função é chamada, ela combina presetArgs e laterArgs e chama a função original fn com esses argumentos.
  • Usando partial, criamos greetHello, uma função que sempre usa "Hello" como saudação. Quando chamada com um nome, retorna a mensagem completa.

Benefícios da Aplicação Parcial

  1. Simplificação: Crie funções mais simples a partir de funções mais complexas

    Suponha que temos uma função que calcula o preço final de um item após aplicar desconto e imposto.

function calculateFinalPrice(price, discount, tax) {
    return price - (price * discount) + (price * tax);
}

Essa função requer três argumentos, tornando-a um pouco inconveniente de usar repetidamente quando o desconto e as alíquotas de imposto são frequentemente os mesmos. Com aplicação parcial, podemos simplificar isso.

javascript— editable

No exemplo acima, applyDiscountAndTax é uma função com aplicação parcial que predefiniu os valores de discount e tax. Isso facilita o cálculo do preço final para diferentes itens sem especificar repetidamente as alíquotas de desconto e imposto.

  1. Reutilização de Código: Reutilize a lógica comum de funções com diferentes argumentos predefinidos

    Imagine que temos uma função que registra mensagens com diferentes níveis de severidade.

function logMessage(level, message) {
    console.log(`[${level}] ${message}`);
}

Podemos criar funções reutilizáveis para diferentes níveis de log usando aplicação parcial.

javascript— editable

Aqui, createLogger é uma função com aplicação parcial que define o argumento level. As funções infoLogger e errorLogger podem agora ser usadas para registrar mensagens com os níveis de log predefinidos, reutilizando a lógica comum de logMessage.

  1. Legibilidade Melhorada: Torna o código mais legível ao decompor funções complexas Considere uma função que formata datas em diferentes estilos.
function formatDate(date, format) {
    const options = { year: 'numeric', month: '2-digit', day: '2-digit' };
    if (format === 'US') {
        options.month = 'long';
    } else if (format === 'EU') {
        options.day = 'numeric';
        options.month = 'numeric';
    }
    return new Date(date).toLocaleDateString(undefined, options);
}

Usando aplicação parcial, podemos criar funções mais legíveis para diferentes formatos de data.

javascript— editable

createDateFormatter aplica parcialmente o argumento format, resultando em funções específicas para formatos de data dos EUA e da Europa. Essa decomposição torna o código mais legível e fácil de entender, pois cada função de formatação é dedicada a um formato específico.

Esses exemplos ilustram como a aplicação parcial em JavaScript pode simplificar funções complexas, melhorar a reutilização de código e aumentar a legibilidade, tornando o código mais fácil de gerenciar e entender.

Currying vs. Aplicação Parcial

Essas duas técnicas são intimamente relacionadas e frequentemente confundidas, mas não são a mesma coisa:

  • Currying transforma uma função de N argumentos em N funções aninhadas que cada uma recebe exatamente um argumento. Uma função totalmente com currying é sempre chamada um argumento por vez: f(a)(b)(c).
  • Aplicação parcial fixa alguns argumentos de uma função e retorna uma nova função que recebe o restante em uma única chamada: g = partial(f, a) e depois g(b, c).

Em resumo: currying é sobre a forma da função (uma cadeia de chamadas unárias), enquanto a aplicação parcial é sobre pré-preencher argumentos. Observe que o helper curry genérico acima é mais flexível do que o currying estrito — ele aceita argumentos em grupos (curriedMultiply(2, 3)(4)), portanto borra a linha e efetivamente também suporta aplicação parcial.

javascript— editable

Boas Práticas para Usar Currying e Aplicação Parcial

Mantenha as Funções Puras

  • Garanta que as funções com currying e aplicação parcial permaneçam puras, sem efeitos colaterais. Isso as torna mais fáceis de raciocinar e testar.

Use Quando Apropriado

  • Use currying e aplicação parcial quando eles se encaixam naturalmente no problema em questão.
  • Evite usar excessivamente essas técnicas, pois elas podem tornar o código mais difícil de entender se não forem usadas com critério.

Aproveite a Composição de Funções

  • Combine funções com currying para criar funcionalidades mais complexas. O currying funciona bem com composição de funções, levando a um código mais modular.

Documentação e Nomenclatura

  • Documente adequadamente as funções com currying e aplicação parcial para indicar seu uso esperado.
  • Use nomes claros e descritivos para as funções a fim de transmitir seu propósito.

Fique Atento a Estas Armadilhas

  • fn.length é não confiável para currying automático. Um helper curry genérico que depende de fn.length se comportará incorretamente com parâmetros padrão ou parâmetros rest, pois esses não são contados. Se uma função os usa, passe a aridade esperada explicitamente em vez de confiar em fn.length.
  • Excesso de currying prejudica a legibilidade. Uma cadeia longa f(a)(b)(c)(d) é mais difícil de ler do que uma única chamada bem nomeada. Recorra ao currying quando ele genuinamente eliminar repetição.
  • Cuidado com this. Arrow functions não têm seu próprio this, portanto uma cadeia com currying escrita com arrows não pode ser usada como um método que depende do objeto chamador. Se você precisar do this dinâmico, consulte vinculação de funções.
Informação

Se você usa currying e aplicação parcial com frequência, considere usar a biblioteca Lodash, que fornece funções utilitárias convenientes como _.curry e _.partial.

Combinando com Métodos de Array

O currying pode ser combinado efetivamente com métodos de array como map, filter e reduce para obter código conciso e expressivo.

javascript— editable

Explicação:

  • A função curriedMultiply é usada para criar multiplyByTwo, uma função que multiplica seu argumento por 2.
  • O array numbers é transformado usando map, aplicando multiplyByTwo a cada elemento, resultando em um novo array de números dobrados.

Conclusão

Currying e Aplicação Parcial em JavaScript oferecem técnicas poderosas para simplificar a composição de funções, melhorar a reutilização de código e aumentar a legibilidade. O currying transforma funções com múltiplos argumentos em uma série de funções unárias, permitindo um código mais flexível e modular. A aplicação parcial permite predefinir argumentos de funções, facilitando a reutilização de código e a simplificação de funções complexas. Ao aproveitar esses conceitos de programação funcional, os desenvolvedores podem escrever código JavaScript mais limpo, conciso e de fácil manutenção.

Prática

Prática
O que é correto sobre Currying em JavaScript?
O que é correto sobre Currying em JavaScript?
Was this page helpful?