Currying is a concept from lambda calculus, but don’t let that freak you out — it’s quite simple to implement.
Currying is a function that takes one argument at a time and returns a new function expecting the next argument. It is a transformation of functions that translates a function from callable as f(a, b, c) into callable as f(a)(b)(c).
In this article, we’re going to explore what currying is in Javascript, why and where you should use currying, and how to implement it with code examples.
Currying simply means evaluating functions with multiple arguments and decomposing them into a sequence of functions with a single argument.
In other terms, currying is when a function — instead of taking all arguments at one time — takes the first one and returns a new function, which takes the second one and returns a new function, which takes the third one, etc. until all arguments are completed.
There are several reasons why currying is ideal:
Currying is a function that accepts multiple arguments. It will transform this function into a series of functions, where every little function will accept one argument:
Noncurried version// const add = (a, b, c)=>{ return a+ b + c } console.log(add(2, 3, 5)) // 10 Curried version// const addCurry =(a) => { return (b)=>{ return (c)=>{ return a+b+c } } } console.log(addCurry(2)(3)(5)) // 10
Currying in Javascript may be a little bit tricky to understand in terms of its definition, but it will become clear as we implement it.
So, let’s dive into more code examples.
First, I’m going to create a simple function that accepts three parameters:
const add =(a, b, c)=>{ return a+b+c } console.log(add(2, 3, 5)) // 10
After outputting this function, the result is 10
.
What happened here is that this function is adding all the parameters of the numbers which we have passed.
Now, this first example is just a simple function that accepts multiple parameters.
How do I convert an existing function to a curried version?
Let’s try this second example and see how we can implement the curry function.
In this example, this function is going to accept one argument and return a series of functions:
const addCurry =(a) => { return (b)=>{ return (c)=>{ return a+b+c } } }
This is the curry implementation of the function. If we output this, the result will be 10
:
console.log(addCurry(2)(3)(5)) // 10
In the first example, we created a function addCurry
that accepted three arguments a
, b
, and c
, added their sum a+b+c
, (2)+(3)+(5), and returned the output as 10
.
This second example showed how we implemented the same function but with a curried version that takes one argument a
and returns a function that takes another argument b
, which returns a function that takes another argument c
, and that function returns their sum, which gave us the same output as example one: 10
.
What we have done here is a nested function, so each of these functions takes one argument that returns another argument and the function doesn’t complete until it receives all parameters.
In this example, we are going to create a simple curry function where a user sends a friend request to his friend John:
function sendRequest(greet){ return function(name){ return function(message){ return `${greet} ${name}, ${message}` } } } sendRequest('Hello')('John')('Please can you add me to your Linkedin network?')
Output:
"Hello John, Please can you add me to your Linkedin network?"
We created a function sendRequest
that requires only one argument, greet
, and it returns the name of the person and the message we want to send to the user. Then, when we invoked the function, it outputted the message.
const getPanCakeIngredients = (ingredient1) =>{ return (ingredient2) => { return (ingredient3) => { return ${ingredient1}, ${ingredient2}, ${ingredient3}; } } } getPanCakeIngredients('Egg')('flour')('milk');
This code example is a basic way of implementing currying.
In the above example, we created a function getPanCakeIngredients
that takes ingredient 1
as a single argument and returns a series of functions that contain the other ingredients we need to make the pancake.
The function isn’t complete until it receives all parameters, which means if the ingredients for the pancake are not complete, the function won’t return any good result.
Here is a code example of advanced currying:
const curry =(fn) =>{ return curried = (...args) => { if (fn.length !== args.length){ return curried.bind(null, ...args) } return fn(...args); }; } const totalNum=(x,y,z) => { return x+y+z } const curriedTotal = curry(totalNum); console.log(curriedTotal(10) (20) (30));
In the example above, we created a function that requires a fixed number of parameters.
It receives a function curry
as the outer function. This function is a wrapper function. It returns another function named curried
, which receives an argument with the spread operator ( ...args)
, and it compares the function length fn length
.
The function length means that whatever the number of parameters we pass here, it will reflect in the length property of the function.
But the argument will increase every time. If the number of the parameters we need is not equal, it is going to return curried
. If we call bind
, this creates a new function and we pass the ( ...args)
.
N.B.,
bind
creates a new function.
As my bonus tip, here is a modern way of implementing currying using the ES6 arrow function. It helps you write less code:
const sendRequest = greet => name => message => `${greet} ${name}, ${message}` sendRequest('Hello')('John')('Please can you add me to your Linkedin network?')
Output:
"Hello John, Please can you add me to your Linkedin network?"
Ready to put currying into action? Here is a simple CodePen example of how to manipulate the DOM using currying:
Curry Dom example
When should I use currying or how should I use currying? * Currying can be used to manipulate a Dom element in Javascript…
Now that you know how currying works, what is the difference between currying and a partial application? This is one question programmers keep asking.
I finally have the answer to this question. But before I dive deeper into this explanation with some code examples, it would be best if we familiarize ourselves with their definitions.
Knowing the definitions aren’t enough for us to understand their differences. You’ve seen currying in action, but this is an example of partial application:
const addPartial=(x,y,z) => { return x+y+z } var partialFunc= addPartial.bind(this,2,3); partialFunc(5); //returns 10
What we did here isn’t a curried version, but we did a partial application of the addPartial
function. We created a simple function that adds a list of numbers and returns their output.
N.B., a function is called a partial application when some of the argument it passes is incomplete.
Currying and partial application are not really different; they are related, but they have different theories and applications.
The partial application converts a function to another function, but with smaller arity.
For developers, currying can feel complicated. While it is tricky to understand, you will learn it better when you implement it in your JavaScript projects.
I have implemented currying in some of my projects and learned by practice. These are some things I have used currying for:
Thanks for reading this article, and please feel free to leave any comments you have. I’m open to learning from you. Cheers!
Debugging code is always a tedious task. But the more you understand your errors, the easier it is to fix them.
LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to see exactly what the user did that led to an error.
LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
4 Replies to "Understanding JavaScript currying"
Not a fan of currying, since I want to make future developers life easier to maintain code.
Simple is always better than complex.
Explanation is literally good. Easy to understand for everyone.
And in the Third example,there will be function instead of const because we haven’t initialize const here so.
Good explanation of currying. Just a note on
const sendRequest(greet){
return function(name){
…
It looks like needs function instead of const in the line to get it to work.
Please indent your examples. Chrome or vscode can do it for you.
It makes it much easier to follow and read.