JavaScript Currying

In JavaScript, there exists an advanced technique of working with functions. It is called carrying. However, it is used not only in JavaScript but also in other programming languages.

Generally, it is a transformation of functions.So, it translates a function from callable likef(a, b, c) to f(a)(b)(c) .

A function can’t be called by currying. What it does is merely transforming.

For a better perception, let’s start at an example:

Javascript function can’t be called by currying
function curry(fn) { // curry(fn) does transforms curry return function (a) { return function (b) { return fn(a, b); }; }; } function sum(a, b) { return a + b; } let currySum = curry(sum); console.log(currySum(10)(20)); // 30

In the example above, there is a helper function curry(fn) that implements currying for a two-argument f.

It’s a simple performance with two wrappers. A wrapper function(a) is the result of curry(func). Once you call curySum(1), the argument is saved in the Lexical Environment. A new wrapper function(b) is returned. Afterward, it is called with argument 2, passing the call to sum .

Here is a more complex example:

function sum(a, b) {
  return a + b;
}
let currySum = _.curry(sum); // using _.curry from lodash library
alert(currySum(10, 20)); // 30, still callable normally
alert(currySum(10)(20)); // 30, called partially

The purpose of Currying

To understand the main purpose of currying, we should check out a real-life example:

function log(date, importance, message) {
  console.log(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}

Here we have log(date, importance, message), which formats and outputs information.

Currying it will look like this:

logs = _.curry(log);

So, the log will work properly after that:

log(new Date(), "DEBUG", "debug"); // log(a, b, c)

In the curried form it will also work:

log(new Date())("DEBUG")("debug"); // log(a)(b)(c)

So, after currying, nothing is lost. Partial functions, also, can be easily generated.

Advanced Currying

Now let’s get into some details and check out more complicated currying with multi-argument functions.

It’s quite brief, as shown below:

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return function (...args2) {
        return curried.apply(this, args.concat(args2));
      }
    }
  };
}

A usage example will look like this:

Javascript fmulti-argument functions by currying
function curry(fn) { return function curried(...args) { if (args.length >= fn.length) { return fn.apply(this, args); } else { return function (...args2) { return curried.apply(this, args.concat(args2)); } } }; } function sum(a, b, c) { return a + b + c; } let currySum = curry(sum); console.log(currySum(10, 20, 30)); // 60, still callable normally console.log(currySum(10)(20, 30)); // 60, currying of 1st arg console.log(currySum(10)(20)(30)); // 60, full currying

The wrapper curried will become the result of curry(fn):

// fn is function to transform
function curried(...args) {
  if (args.length >= fn.length) { // (1)
    return fn.apply(this, args);
  } else {
    return function pass(...args2) { // (2)
      return curried.apply(this, args.concat(args2));
    }
  }
};

Running it will lead to two if execution branches. The first is calling now. In case the passed args count is similar to the original function includes in its definition or longer, then the call should be passed to it. The second is getting a partial. In another way, the fn is not called yet. Another pass is returned. It can re-apply curried providing previous arguments with the new ones. Afterward, on a new call, either a new partial or the result will be received.

It is essential to note that for the currying, a fixed number of arguments is required. So, a function using rest parameters f(...args) like will not be curried like that.

Summary

In JavaScript, currying represents a transform, which turns the callable f(a,b,c) to f(a)(b)(c) . Normally, JavaScript implementations keep the function callable, as well as return the partial, once the argument counts are less than needed. Getting partials is also easy with currying.

Practice Your Knowledge

What is correct about Currying in JavaScript?

Quiz Time: Test Your Skills!

Ready to challenge what you've learned? Dive into our interactive quizzes for a deeper understanding and a fun way to reinforce your knowledge.

Do you find this helpful?