Understanding Currying in JavaScript

Understanding Currying in JavaScript

Introduction

I have been an advocate for writing efficient codes; React Hooks- The Deep Cuts and Asynchronous JavaScript are some proof. Currying is another approach to producing efficient codes.

Currying is a technique used in functional programming where a function that accepts multiple parameters splits into others, each taking one argument. This technique allows the creation of more specialized reusable functions with different arguments. It is a method to create new functions from existing ones by partially applying arguments. You get to write more efficient and readable code by breaking down complex functions into concise, reusable parts.

This article explores the concept of currying in JavaScript, how to implement it with various code samples, and its benefits.

Currying in play

Currying involves splitting up a function that accepts multiple arguments into several ones that only take one parameter each. It allows you to provide arguments upfront while postponing the provision of others.

Example: Let's look at an instance of currying. We have a function that evaluates the multiplication of three numbers.

function multiply(a, b, c) {
  return a * b * c;
}
We can convert this function into a curried function using the following code:
function multiply(a) {
  return function(b) {
    return function(c) {
      return a * b * c;
    }
  }
}

multiply(2)(3)(7); // 42

We created three functions by this code, each of which only accepts one input. The 1st function takes the first argument of the original one and returns a new one that takes the second argument. The 2nd function takes the second argument and gives a new one that takes the 3rd argument. The third function takes the third argument and returns the final result. Hence, calling the curried function to evaluate the three numbers printed 42

Implementing currying in JavaScript

To implement currying in JavaScript, we need to write a new function that accepts the first argument and returns another that takes the second argument till the passing of all arguments. But you can implement curry in various forms, all of which include;

Using a closure:

It requires creating a new function that accepts a single argument and returns a second function that takes a second argument, and so forth. The previous arguments have access to the returned function via closure. Example:

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

const addFive = add(5);
console.log(addFive(3)); // Output: 8
console.log(addFive(7)); // Output: 12

In this example, add() is defined using currying, closure allows us to "remember" the value even after the outer add function has finished executing. To use the add function, we first call it with a value for a, which returns a new function that you call with b. This new function saves to a variable (in this case, addFive) to be used multiple times with different values of b. The method of using closures helps you build more adaptable, reusable functions for a variety of use and to produce more complicated functionality.

Using the bind() method:

The bind() method creates a new function with a value and arguments. We can use it to partially apply arguments to a function and return a new function that accepts the rest argument.

Example:

function multiply(a, b) {
  return a * b;
}

const multiply10 = multiply.bind(null, 10);
console.log(multiply10(3)); //Output: 30

You can construct multiple bind() calls together to create functions that take more than one argument.

Example:

function multiply(a, b, c) {
  return a * b * c;
}

const curriedMultiply = multiply.bind(null, 10).bind(null, 20);

console.log(curriedMultiply(3)); //Output: 600

In this example, the first call to bind() fixes the value of the first argument (a) to 10, and the second call to bind() fixes the value of the second argument (b) to 20. The third argument (c) does not have a value, but it came in the calling of the curriedMultiply function. In calling curriedMultiply(3), the value (3) assigns to the remaining unfixed argument c, and the function returns the product of a * b * c, which is 10 * 20 * 3 = 600.

Using arrow functions:

Arrow functions have a concise syntax and can be used to create a curry function.

Example:

const multiply = (x, y, z) => x * y * z;

// A curried version of the add function using arrow functions
const curryMultiply = x => y => z => multiply(x, y, z);

// Usage
console.log(multiply(1, 2, 3)); // Output: 6

const multiplyFirst = curryMultiply(1);
console.log(multiplyFirst(3)(3)); // Output: 9

const multiplySecond = curryMultiply(2);
console.log(multiplySecond(3)(4)); // Output: 24

const multiplyThird = curryMultiply(3);
console.log(multiplyThird(4)(5)); // Output: 60

curryMultiply defines the arrow functions on x, y, and z. It takes a single argument x and returns a new function that takes an argument y and gives another that takes an argument z. The innermost function calls the original multiply function with the arguments x, y, and z. When we call multiplyFirst(3)(3), the inner function returns the product of 1, 3, and 3, = 9. Similarly, multiplySecond(3)(4) gives the result of 2, 3, and 4, which is 24, and multiplyThird(4)(5) returns the product of 3, 4, and 5, which is 60.

Building a project using currying

The project is a simple quiz application. It allows users to select a topic and answer related questions. The questions and answers stay in an object; currying create functions allowing users to pick a topic and respond.

Why you should use currying - (benefits of currying)

Currying is a powerful technique that can help developers write more efficient and readable code in JavaScript, plus there are benefits to it. Some include;

Reusability

Currying allows developers to create partially reusable functions for specific use cases in multiple contexts. It reduces code duplication and makes the codebase easier to maintain. By breaking down a function into smaller ones, we can reuse those smaller functions in different contexts.

Readability

Currying can make code more readable by breaking down complex functions into smaller, more manageable parts. It can make it easier to understand and maintain large codebases.

Flexibility

Currying provides developers with flexibility when designing functions used with a varying number of arguments. A function can be composed of others by partially applying existing ones to create complex behavior. It allows developers to create composable, modular, and easily testable functions.

Customizability

By currying, you can create more specialized functions tailored to your needs. You can also customize it for simplicity. Currying simplifies complex functions by breaking them into smaller, more manageable parts.

Wrapping up

Currying gives you the ability to do more with your function and still achieve optimization, modularity, ease, readability, reusability, and others. It also offers ways to implement it in JavaScript; if you have been looking for more ways to hack optimizing your JavaScript code, currying is your guy.

Thank you for reading.

You can follow me on Twitter and LinkedIn.

Buy me coffee.

Further Reference

Understanding JavaScript Currying - Ezekiel Lawson

How to Use Currying and Composition in JavaScript - Tobias Parent