Understanding JavaScript Currying with a Real-World Application

RMAG news

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 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
  • 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!✨

Please follow and like us:
Pin Share