Have you seen the word "currying" in JavaScript and wondered what it meant? In this blog, we'll look at the concept of currying, break it down with easy examples, and show how it can be used in a real-world scenario to make your code clearer and more flexible.
š” What is Currying?
Currying is a functional programming approach in which a function uses each of its arguments one at a time, rather than all at once. A curried function returns another function that accepts the next parameter until all arguments have been provided.
In simple terms, currying converts a function with several arguments into a series of functions, each of which takes one argument.
Let's understand using a real-life analogy and code:
š Make a Burger
Think about ordering a burger at a fast-food eatery. A chef will prepare your burger layer by layer:
Layer 1: The bun (first argument).
Layer 2: The patty (second argument).
Layer 3: Toppings (third argument).
Let's write code for the above scenario using Regular Function and Curried Function.
š Using a Regular Function:
In a regular function, all the ingredients are passed at once as arguments.
function makeBurger(bun, patty, topping) {
return `Your burger has: ${bun} bun, ${patty} patty, and ${topping} topping.`;
}
const myBurger = makeBurger("Sesame", "Mix Veg", "Cheese");
console.log(myBurger); // Output: Your burger has: Sesame bun, Mix Veg patty, and Cheese topping.
š Using a Curried Function:
In a curried function, you pass one ingredient at a time.
function makeBurgerCurried(bun) {
return function (patty) {
return function (topping) {
return `Your burger has: ${bun} bun, ${patty} patty, and ${topping} topping.`;
};
};
}
// Example usage
const chooseBun = makeBurgerCurried("Sesame");
const choosePatty = chooseBun("Mix Veg");
const myCurriedBurger = choosePatty("Cheese");
console.log(myCurriedBurger); // Output: Your burger has: Sesame bun, Mix Veg patty, and Cheese topping.
āļø Explanation:
First Call: makeBurgerCurried("Sesame")
receives "Sesame"
and returns a new function that waits for patty.
const chooseBun = makeBurgerCurried("Sesame");
console.log(chooseBun);
/* Output:
Ę (patty) {
return function (topping) {
return `Your burger has: ${bun} bun, ${patty} patty, and ${topping} topping.`;
};
} */
Second Call: chooseBun("Mix Veg")
receives "Mix Veg"
and returns another function that waits for topping.
const choosePatty = chooseBun("Mix Veg");
console.log(choosePatty);
/* Output:
Ę (topping) {
return `Your burger has: ${bun} bun, ${patty} patty, and ${topping} topping.`;
} */
Third Call: choosePatty("Cheese")
receives "Cheese"
and completes the function chain, returning the final burger description.
const myCurriedBurger = choosePatty("Cheese");
console.log(myCurriedBurger);
// Output: Your burger has: Sesame bun, Mix Veg patty, and Cheese topping.
ā Simplified Arrow Function for Currying
You can simplify the curried function using arrow functions:
const curriedArrowFunction = (bun) => (patty) => (topping) =>
`Your burger has: ${bun} bun, ${patty} patty, and ${topping} topping`
const myArrowFunction = curriedArrowFunction("Sesame")("Mix Veg")("Cheese")
console.log(myArrowFunction); // Your burger has: Sesame bun, Mix Veg patty, and Cheese topping
āļø Why Use Currying?
Currying is especially handy when you need to reuse a function with specific arguments. It promotes code reuse, readability, and modularity.
š» Real-World Application: Discount Calculator
Imagine you're developing an e-commerce platform. Discounts are calculated according to the type of customer:
- Regular customers receive a 10% discount.
- Premium customers receive a 20% discount.
Now let's build this using the Regular function first:
š Using a Regular Function:
Using a regular function for a discount calculator may result in less flexibility and reusable code. You'd have to write separate functions for each type of customer or pass all parameters every time the discount is calculated.
function calculateDiscount(customerType, price) {
if (customerType === "Regular") {
return price * 0.9; // 10% discount
} else if (customerType === "Premium") {
return price * 0.8; // 20% discount
}
}
console.log(calculateDiscount("Regular", 100)); // Output: 90
console.log(calculateDiscount("Premium", 100)); // Output: 80
ā Limitations of Regular Function:
- Repetitive Logic: You must pass customerType every time, even if it does not change during several calculations.
- No Reusability: If you want to apply a discount to one customer type across multiple transactions, you must specify the type each time.
- Scalability Issues: Adding additional customer types or discount rules complicates the function and makes it more difficult to maintain.
Now let's build this application using the Curried function:
š Using a Curried Function:
Currying allows you to create reusable functions for various customer types. Instead of continuously giving the same parameters, you can configure the discount logic for each consumer type.
function createDiscountCalculator(discountRate) {
return function (price) {
return price * (1 - discountRate);
};
}
// Create specific calculators for different customer types
const regularDiscount = createDiscountCalculator(0.1); // 10% discount
const premiumDiscount = createDiscountCalculator(0.2); // 20% discount
// Use them for calculations
console.log(regularDiscount(100)); // Output: 90
console.log(premiumDiscount(100)); // Output: 80
console.log(regularDiscount(200)); // Output: 180
ā Advantages of the Curried Function:
-
Reusability: Once
regularDiscount
orpremiumDiscount
is specified, you will not need to specify the discount rate again for further transactions. - Cleaner Code: The logic is separate and focused. Each function has a single responsibility: to define and apply the discount rate.
- Scalability: Creating new customer types is simple. For example:
const studentDiscount = createDiscountCalculator(0.15); // 15% discount
console.log(studentDiscount(100)); // 85
-
Improved Readability: The code clearly states its purpose. A
regularDiscount
function specifies the discount logic for regular customers.
Conclusion
Currying may appear complex at first, but as we've seen, it's a powerful concept for simplifying function creation and making your code clearer and more reusable.
Now that you get an idea of it, try currying in your next project and see the magic happen!
Share Your Thoughts
Have you ever used currying in your projects? What were the problems or benefits you experienced? Please let me know in the comments below!
Happy coding!āØ
Top comments (23)
You are totally right a curryng is a great tool of JS programming.
Great to put into the table!
But the standard function is a different question.
A way more elegant declaration of currying is a arrow function.
I am using this technic in my program, there you can found the repo link in this post: dev.to/pengeszikra/javascript-grea...
Thanks for the comment!
You are correct, arrow functions are an easier way to write curried functions. They provide clarity and context, making them useful for this purpose.
I appreciate that you included a practical application of currying in your program. It's always interesting to see how theoretical concepts apply to practical implementations. I'll surely check that.
But this example (as is one of the above) isn't really currying, it is a predetermined order and is not reusable - It isn't returning a function that says "add the next argument" it is only returning a series of pre-determined arguments.
If I want to add, say, a layer that is "tomato" and another layer that is "onion" this function breaks.
You totally right this example functions is don't really usefull.
Maybe this is much usefull example, to combine a different dependency
on the right moment.
Currying is usually seen as one of those advanced concepts. Breaking a function into smaller parts definitely improves reusability and clarity. I like it because it eliminates the need to repeatedly pass the same arguments and this makes your code more flexible and more maintainable. Good job!
Thanks for the comment!
Yeah, currying improves reusability and clarity by dividing down functions. It eliminates unnecessary parameters, increasing code flexibility and maintainability.
I'm glad you find it useful.
I am happy to see many devs are shifting from OOP to Functional programming. Please stop using Class and this keywords in JavaScript. Thank me later.
Still many companies ask bind, call and apply uses in interviews. React stopped using Class components too.
There are many cases where a class based system as well as prototypal syntax make more sense, such as games for example. Functional Programming is great for operations on data, but can create code spaghetti chaos instead of organized properties when dealing with private getter/setters. Sometimes you just need encapsulation.
Completly agree with you. Use the right tool for the right problem, OOP for modeling, FP for creating abstractions.
Nice points, everyone! Each approach works in its own context: OOP provides structure and encapsulation, while FP simplifies data operations and abstractions. The important thing is using the appropriate approach for the correct challenge.
The most common and useful case for currying is āconfiguringā a function that needs a specific signature.
So if you have to provide a call back to an onclick event of a button (which must be (e) => void), but need to pass it arguments first, then currying is brilliant for it.
const configureMyOnClick = (dependency) => (e) => {
If (dependency)
// do a thing.
}
Thank you for sharing the example! You are correct, currying is ideal for such situations. It enables functions to be modified to specific requirements, such as passing dependencies while keeping the necessary signature. A great real-world use case!
This was really one of the best explanation of currying with simple examples... Really liked it!!
Thanks for appreciating
Iām glad you like it.
Great
Thanks for appreciating
Mind-blowing
Thanks for appreciating
I likes this and went to googling more about it and I found... somewhere that marked Currying as Miscellaneous. What is your take on this?
Thank you for your comment!
Currying may be considered "miscellaneous" by some, but I believe it is a useful tool in functional programming. It benefits in applications such as partial application or developing reusable, flexible functions. While it may not be used every day, it is definitely worth learning!
I love the simplicity of your writing... Awesome Content šš»
Thanks for appreciating
Currying is garbage now that Javascript supports classes. You can do anything more manageable with a class. And there is a 1 to 1 syntax change for currying to classes
typescript to es3 converts class to function currying, for example
Just stop with this legacy syntax. Unless you really need to write es3 code