Practical Examples of Currying in JavaScript

Currying is a functional programming technique that transforms a multi-argument function into a sequence of single-argument functions, improving modularity and reusability.
In this blog, we explore 6 real-world examples of currying in JavaScript.

👉 For a deeper dive into the theory behind currying, check out our companion blog — Functional Programming in JavaScript: Partial Application and currying


Practical Examples of Currying

Below are practical examples demonstrating how currying can be applied in real-world JavaScript scenarios.

Example 1: Formatting Log Messages

Currying creates reusable logging functions for different log levels.

const formatLog = level => message => `[${level}] ${message}`;
const logError = formatLog('ERROR');
const logInfo = formatLog('INFO');

console.log(logError('Connection failed')); // [ERROR] Connection failed
console.log(logInfo('User logged in')); // [INFO] User logged in

Explanation: The formatLog function is curried to first accept a level, then a message, creating specialized functions like logError.

Example 2: Dynamic Discount Calculator

Currying simplifies creating functions for specific discount percentages.

const discount = percent => price => price * (1 - percent / 100);
const tenPercentOff = discount(10);
const twentyPercentOff = discount(20);

console.log(tenPercentOff(100)); // 90
console.log(twentyPercentOff(100)); // 80

Explanation: discount is curried to fix the percentage, creating reusable functions for specific discounts.

Example 3: DOM Manipulation

Currying streamlines DOM updates by pre-configuring element selectors.

const updateElemText = id => content => (document.querySelector(`#${id}`).textContent = content);
const updateHeaderText = updateElemText('header');
updateHeaderText('Hello World');

// HTML: <div><h1 id="header">Hello World</h1></div>

Explanation: The curried function specializes in updating a specific DOM element’s text.

Example 4: Operation-Based Calculator

Create a curried function that performs different operations based on a parameter.

const calculate = operation => a => b => {
  if (operation === 'sum') return a + b;
  if (operation === 'multiply') return a * b;
  if (operation === 'divide') return a / b;
  if (operation === 'subtract') return a - b;
  return 'Invalid Operation';
};
console.log(calculate('sum')(2)(4)); // 6
console.log(calculate('multiply')(2)(4)); // 8

Explanation: The function takes an operation type and two numbers, performing the specified operation in a curried manner.

Example 5: Infinite Argument Summation

Handle an arbitrary number of arguments using recursion.

const sum = a => b => b !== undefined ? sum(a + b) : a;
console.log(sum(1)(2)(3)()); // 6
console.log(sum(1)(2)(3)(4)()); // 10

Step-by-Step Explanation:

  1. Define the Curried Function: sum is defined as a curried function using arrow functions. It takes an initial argument a and returns a function that expects b.

  2. Check for b: If b is provided (i.e., not undefined), the function returns a new sum function with the accumulated value a + b. This enables recursive calls for more arguments.

  3. Base Case: When b is undefined (e.g., sum(1)(2)(3)()), the function returns the accumulated value a.

  4. Execution Example:

    • sum(1) returns a function with a = 1, expecting b.

    • sum(1)(2) computes a + b = 1 + 2 = 3, returns a new sum with a = 3.

    • sum(1)(2)(3) computes a + b = 3 + 3 = 6, returns a new sum with a = 6.

    • sum(1)(2)(3)() has b = undefined, so it returns a = 6.

    • For sum(1)(2)(3)(4)(), the process continues until () returns 1 + 2 + 3 + 4 = 10.

Example 6: Generic Curry Function

Convert any function into a curried version.

function curry(func) {
  return function curried(...args) {
    if (args.length >= func.length) {
      return func(...args);
    }
    return (...next) => curried(...args, ...next);
  };
}
const join = (a, b, c) => `${a}_${b}_${c}`;
const curriedJoin = curry(join);
console.log(curriedJoin(1, 2, 3)); // '1_2_3'
console.log(curriedJoin(1)(2, 3)); // '1_2_3'
console.log(curriedJoin(1, 2)(3)); // '1_2_3'

Step-by-Step Explanation:

  1. Define the Curry Function: The curry function takes a function func and returns a curried function that handles arguments.

  2. Check Argument Count: curried uses the spread operator (...args) to collect arguments. If the number of arguments (args.length) is at least the number required by func (func.length), it calls func with all arguments.

  3. Return New Function: If fewer arguments are provided, curried returns a new function that collects additional arguments (...next) and combines them with args for the next call.

  4. Execution Example:

    • curriedJoin(1, 2, 3): args = [1, 2, 3], func.length = 3, so join(1, 2, 3) is called, returning '1_2_3'.

    • curriedJoin(1): args = [1], fewer than 3, returns a function expecting more arguments.

    • curriedJoin(1)(2, 3): Combines args = [1] with next = [2, 3], calls join(1, 2, 3), returns '1_2_3'.

    • curriedJoin(1, 2)(3): First call stores args = [1, 2], second call adds 3, calls join(1, 2, 3), returns '1_2_3'.


Thanks for checking out the blog! 🙌
Tried out the examples? Let me know how it went or drop your favourite use case for currying in the comments!

0
Subscribe to my newsletter

Read articles from Deepthi Purijala directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Deepthi Purijala
Deepthi Purijala

Full Stack Developer with hands-on experience of more than 1 year. Proficient in both Back-end and Front-end technologies, with a strong commitment to delivering high-quality code