Currying in JavaScript is a process in functional programming in which you can transform a function with multiple arguments into a sequence of nesting functions. It returns a new function that expects the next argument inline.
In other words, instead of a function taking all arguments at one time, it takes the first one and returns a new function, which takes the second one and returns a new function, which takes the third one, and so on, until all arguments have been fulfilled.
What Is Currying in JavaScript?
Currying in JavaScript transforms a function with multiple arguments into a nested series of functions, each taking a single argument. Currying helps you avoid passing the same variable multiple times, and it helps you create a higher order function.
That is, when we turn a function call sum(1,2,3)
into sum(1)(2)(3)
.
The number of arguments a function takes is also called arity
.
function sum(a, b) {
// do something
}
function _sum(a, b, c) {
// do something
}
The function sum
takes two arguments (two-arity function) and _sum
takes three arguments (three-arity function).
Curried functions are constructed by chaining closures and by defining and immediately returning their inner functions simultaneously.
Why Is Currying in JavaScript Useful?
- Currying helps you avoid passing the same variable again and again.
- It helps to create a higher order function.
Currying transforms a function with multiple arguments into a sequence/series of functions, each taking a single argument.
For example:
function sum(a, b, c) {
return a + b + c;
}
sum(1,2,3); // 6
As you can see, this is a function with full arguments. Let’s create a curried version of the function and see how we would call the same function (and get the same result) in a series of calls:
function sum(a) {
return (b) => {
return (c) => {
return a + b + c
}
}
}
console.log(sum(1)(2)(3)) // 6
We could even separate this sum(1)(2)(3)
to understand it better:
const sum1 = sum(1);
const sum2 = sum1(2);
const result = sum2(3);
console.log(result); // 6
How Does Currying in JavaScript Work?
Let’s look at how currying works. We passed 1
to the sum
function:
let sum1 = sum(1);
It returns the function:
return (b) => {
return (c) => {
return a + b + c
}
}
Now, sum1
holds the above function definition, which takes an argument b
.
We called the sum1
function, passing in 2
:
let sum2 = sum1(2);
The sum1
will return the third function:
return (c) => {
return a + b + c
}
The returned function is now stored in the sum2
variable.
sum2
will be:
sum2 = (c) => {
return a + b + c
}
When sum2
is called with 3
as the parameter const result = sum2(3);
, it does the calculation with the previously passed in parameters: a = 1
, b = 2
and returns 6
.
console.log(result); // 6
The last function only accepts the c
variable, but it will perform the operation with other variables whose enclosing function scope has long since returned. It works nonetheless because of Closure
.
Currying vs. Partial Application in JavaScript
Some might start to think that the number of nested functions a curried function has depends on the number of arguments it receives. Yes, that makes it a curry.
Let’s take same sum
example:
function sum(a) {
return (b, c) => {
return a * b * c
}
}
It can be called like this:
let x = sum(10);
x(3,12);
x(20,12);
x(20,13);
// OR
sum(10)(3,12);
sum(10)(20,12);
sum(10)(20,13);
The above function expects three arguments and has two nested functions, unlike our previous version, which expected three arguments and had three nesting functions.
This version isn’t a curry. We just did a partial application of the sum
function.
Currying and partial application are related because of closure, but they are different concepts.
Partial application transforms a function into another function with smaller arity.
function sum1(x, y, z) {
return sum2(x,y,z)
}
// to
function sum1(x) {
return (y,z) => {
return sum2(x,y,z)
}
}
For currying, it would look like this:
function sum1(x) {
return (y) = > {
return (z) = > {
return sum2(x,y,z)
}
}
}
Currying creates nesting functions according to the number of the arguments of the function. Each function receives an argument. If there is no argument, there is no currying.
Here’s how you can develop a function that takes a function and returns a curried function:
function currying(fn, ...args) {
return (..._arg) => {
return fn(...args, ..._arg);
}
}
The above function accepts a function (fn
) that we want to curry and a variable number of parameters(…args
). The rest operator is used to gather the number of parameters after fn
into …args
.
Next, we return a function that also collects the rest of the parameters as …_args
. This function invokes the original function fn
passing in …args
and …_args
through the use of the spread operator as parameters. Then, the value is returned to the user.
Now, we can use the above function to create a curry function.
function sum(a,b,c) {
return a + b + c
}
let add = currying(sum,10);
add(20,90); // 120
add(70,60); // 140
Closure makes currying possible in JavaScript. I hope you have learned something new about currying.