Currying in JavaScript

Currying in JavaScript

·

2 min read

Currying a special technique for functions. It will not execute the function, but convert the function to have the ability to be partially applied.

For example, if we have a function f(a, b, c). With currying, we can make this function call like this f(1)(2)(3).

function curry(func) {};

function f(a, b, c) {};
f(1, 2, 3); // original function call like this

// convert it using curry function
f = curry(f);

// then we can call the function like this
f(1, 2, 3);
f(1, 2)(3);
f(1)(2)(3);
f(1)(2, 3);
// ...

As you can see, only when we have enough parameter, then the original function get executed. So with this idea, we can write a currying function like below.

function curry(func) {
    let allArgs = [];
    return function inner(...args) {
        allArgs.push(...args);
        if (allArgs.length >= func.length) {
            const result = func(...allArgs);
            allArgs = []
            return result;
        } else {
            return inner;
        }
    };
}

We use closure variable to store all arguments. So if the number of arguments is enough, then we call the original function, if not we just return the inner function again.

Another solution I learn from Currying is more elegant, code is like below.

function curry(func) {
    return function inner(...args1) {
        if (args1.length >= func.length) {
            return func.apply(null, args1);
        } else {
            return function (...args2) {
                return inner.apply(null, args1.concat(args2));
            };
        }
    };
}

In this solution, double closures are used. The first one is the inner function. Its arguments are used to store all the arguments. If current arguments are not enough, we return a second function, which use the first function's arguments variable to store previous arguments.

Now we can run this currying function like below.

const a = 1;
const b = 2;
const c = 3;
var curriedAbc = curry(abc);
curriedAbc(a)(b)(c);
curriedAbc(a, b)(c);
curriedAbc(a)(b, c);
curriedAbc(a, b, c);