DEV Community

Cover image for Understanding JavaScript Currying with a Real-World Application
Richa
Richa

Posted on ā€¢ Edited on

169 3 8 3 6

Understanding JavaScript Currying with a Real-World Application

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.
Enter fullscreen mode Exit fullscreen mode

šŸ“Œ 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.
Enter fullscreen mode Exit fullscreen mode

āœļø 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.`;
        };
} */
Enter fullscreen mode Exit fullscreen mode

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.`;
} */
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

ā­ 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
Enter fullscreen mode Exit fullscreen mode

ā‰ļø 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
Enter fullscreen mode Exit fullscreen mode

āž– 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
Enter fullscreen mode Exit fullscreen mode

āž• Advantages of the Curried Function:

  • Reusability: Once regularDiscount or premiumDiscount 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
Enter fullscreen mode Exit fullscreen mode
  • 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!āœØ

šŸ’” One last tip before you go

Tired of spending so much on your side projects? šŸ˜’

We have created a membership program that helps cap your costs so you can build and experiment for less. And we currently have early-bird pricing which makes it an even better value! šŸ„

Check out DEV++

Top comments (23)

Collapse
 
pengeszikra profile image
Peter Vivo ā€¢ ā€¢ Edited

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.

/** @type {(bun:string) => (patty:string) => (topping:string) => string} */
const makeBurgerCurried = 
   (bun) =>
   (patty) =>
   (topping) =>
      `Your burger has: ${bun} bun, ${patty} patty, and ${topping} topping.`
;
Enter fullscreen mode Exit fullscreen mode

I am using this technic in my program, there you can found the repo link in this post: dev.to/pengeszikra/javascript-grea...

Collapse
 
thedevricha profile image
Richa ā€¢

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.

Collapse
 
the_riz profile image
Rich Winter ā€¢

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.

Collapse
 
pengeszikra profile image
Peter Vivo ā€¢

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.

const specificEventHandler = (state) => (event) => specificEventProcessing(event, state);

<button key={id} onClick={eventHandler(id)} />
Enter fullscreen mode Exit fullscreen mode
Collapse
 
documendous profile image
Documendous ā€¢

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!

Collapse
 
thedevricha profile image
Richa ā€¢

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.

Collapse
 
vetrivendhan_b_a885118f74 profile image
Vetrivendhan B ā€¢

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.

Collapse
 
the_riz profile image
Rich Winter ā€¢

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.

Collapse
 
juan_labrada_42e0d23118f4 profile image
Juan Labrada ā€¢

Completly agree with you. Use the right tool for the right problem, OOP for modeling, FP for creating abstractions.

Thread Thread
 
thedevricha profile image
Richa ā€¢

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.

Collapse
 
chris_lamb_7d72a6e849b5f7 profile image
Chris Lamb ā€¢ ā€¢ Edited

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.
}

Collapse
 
thedevricha profile image
Richa ā€¢

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!

Collapse
 
_faisaldeshmukh_ profile image
Mohammad Faisal Deshmukh ā€¢

This was really one of the best explanation of currying with simple examples... Really liked it!!

Collapse
 
thedevricha profile image
Richa ā€¢

Thanks for appreciating
Iā€™m glad you like it.

Collapse
 
arushkumar profile image
Arush Kumar ā€¢

Great

Collapse
 
thedevricha profile image
Richa ā€¢

Thanks for appreciating

Collapse
 
yatendra_tyagi_5c61cc13c5 profile image
Yatendra Tyagi ā€¢

Mind-blowing

Collapse
 
thedevricha profile image
Richa ā€¢

Thanks for appreciating

Collapse
 
quynhd3 profile image
quynhd ā€¢

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?

Collapse
 
thedevricha profile image
Richa ā€¢

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!

Collapse
 
difficultworld24 profile image
Kartik Sharma ā€¢

I love the simplicity of your writing... Awesome Content šŸ‘šŸ»

Collapse
 
thedevricha profile image
Richa ā€¢

Thanks for appreciating

Collapse
 
tamusjroyce profile image
tamusjroyce ā€¢

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

Visualizing Promises and Async/Await šŸ¤Æ

async await

Learn the ins and outs of Promises and Async/Await!

šŸ‘‹ Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay