Mastering Currying in JavaScript 🌟
Jagroop Singh

Jagroop Singh @jagroop2001

About: 👨‍💻 Full Stack Developer | 🤖 Machine Learning Developer | 🤝 Dev Relations Pro – 💼 Available for Hire | 24k+ Followers | 355k+ Views

Location:
India
Joined:
Apr 5, 2022

Mastering Currying in JavaScript 🌟

Publish Date: Nov 21 '24
60 17

JavaScript is filled with cool features, and one of the most mind-blowing concepts is currying. Don’t worry if it sounds fancy—by the end of this blog, you’ll not only understand currying but also be able to impress your developer buddies! 💻🔥


🧐 What is Currying?

Currying is a way to transform a function with multiple arguments into a sequence of functions, each taking a single argument. It’s like serving a meal one dish at a time instead of all at once! 🍽️

Read this once again !!


🍰 Why Use Currying?

  1. Reusability: You can create specialized versions of functions.
  2. Readability: Makes your code look cleaner and more modular.
  3. Functional Programming Vibes: Functional programming fans 💛 currying.

🚀 Examples

Let’s jump straight into some examples:

Basic Example

// Normal function
function add(a, b) {
    return a + b;
}
console.log(add(2, 3)); // 5

// Curried version
function curriedAdd(a) {
    return function (b) {
        return a + b;
    };
}
console.log(curriedAdd(2)(3)); // 5
Enter fullscreen mode Exit fullscreen mode

🎉 Boom! Now you can call curriedAdd(2) and get a reusable function to add 2 to anything!

const add2 = curriedAdd(2);
console.log(add2(5)); // 7
console.log(add2(10)); // 12
Enter fullscreen mode Exit fullscreen mode

Currying with Arrow Functions 🏹

Who doesn’t love short, clean arrow functions?

const multiply = (a) => (b) => a * b;

console.log(multiply(3)(4)); // 12

// Make a multiplier of 3
const triple = multiply(3);
console.log(triple(5)); // 15
console.log(triple(10)); // 30
Enter fullscreen mode Exit fullscreen mode

Real-World Example 🌐

Imagine a filter function for a shopping app:

const filterByCategory = (category) => (product) => product.category === category;

const products = [
    { name: "Shoes", category: "Fashion" },
    { name: "Laptop", category: "Electronics" },
    { name: "T-shirt", category: "Fashion" },
];

const isFashion = filterByCategory("Fashion");

console.log(products.filter(isFashion));
// Output: [ { name: "Shoes", category: "Fashion" }, { name: "T-shirt", category: "Fashion" } ]
Enter fullscreen mode Exit fullscreen mode

Breaking Down Complex Problems 🧩

Currying makes it easy to break problems into smaller, manageable parts.

const greet = (greeting) => (name) => `${greeting}, ${name}!`;

const sayHello = greet("Hello");
console.log(sayHello("Alice")); // Hello, Alice!
console.log(sayHello("Bob"));   // Hello, Bob!

const sayGoodMorning = greet("Good Morning");
console.log(sayGoodMorning("Charlie")); // Good Morning, Charlie!
Enter fullscreen mode Exit fullscreen mode

🌟 Advanced Currying with Utility Functions

Don’t want to manually curry functions? Let’s write a helper function:

const curry = (fn) => (...args) =>
    args.length >= fn.length
        ? fn(...args)
        : curry(fn.bind(null, ...args));

// Example:
const sum = (a, b, c) => a + b + c;
const curriedSum = curry(sum);

console.log(curriedSum(1)(2)(3)); // 6
console.log(curriedSum(1, 2)(3)); // 6
console.log(curriedSum(1)(2, 3)); // 6
Enter fullscreen mode Exit fullscreen mode

🤔 Tricky Question Time!

Here's a fun one to tease your brain 🧠:

const add = (a) => (b) => b ? add(a + b) : a;

console.log(add(1)(2)(3)(4)()); // ❓
Enter fullscreen mode Exit fullscreen mode

What do you think the output is? Share your thoughts below! 👇


🏁 Wrapping Up

Currying is a powerful technique that simplifies your code, makes it reusable, and adds a touch of elegance. So, start currying your functions and bring the spice of functional programming to your JavaScript code! 🌶️

Happy coding! 💻✨

Comments 17 total

  • john
    johnNov 21, 2024

    `

    `
    const add = (a) => (b) => b ? add(a + b) : a;

    console.log(add(1)(2)(3)(4)()); // ❓
    `
    `
    It's answer would be : 10 ( if I uderstand the concept clearly)

    • Jagroop Singh
      Jagroop SinghNov 21, 2024

      Yes it's correct !!
      What's your approach to solve this.

  • Amos Murmu
    Amos MurmuNov 22, 2024

    How does utility function works?? It's confusing
    What does this code do
    fn(...args)
    : curry(fn.bind(null, ...args));

    • Charles F. Munat
      Charles F. MunatNov 22, 2024

      This is actually a pretty smart bit of code. It allows you to curry any JavaScript function (remember that all functions must take at least one parameter, else they are effectively constants).

      The function itself is curried, so you can pass in your function (sum) and get back a function that takes one or more arguments, which we collect into an array called args: (...args).

      We can check how many arguments sum expects with length, hence fn.length here returns 3 because sum(a, b, c).

      curriedSum(1, 2, 3) // returns 6
      
      Enter fullscreen mode Exit fullscreen mode

      So when the curried sum is called, we check if the number of arguments passed in (args) is equal to the number of parameters expected (fn.length). If all the arguments are there, then we just call the sum function with them, spreading the args back out: fn(...args).

      But if too few arguments have been passed, e.g., sum(1, 2), then we bind those arguments to their parameters (here, a = 1 and b = 2) and return a closure that expects the third argument (c). When it gets that argument, it will meet the condition fn.length = args.length, so it will simply call the function with the remaining argument(s).

      curriedSum(1, 2) // returns (c) => sum(1, 2, c)
      
      Enter fullscreen mode Exit fullscreen mode

      Hope that helps.

  • davepile
    davepileNov 22, 2024

    This is well writen and the examples are very easy to follow and illustrate your points well. I have read a few articles about currying from time to time, but it always feels like a bit of mental gymnastics is required to use it. I can follow the examples, but its not something I can look at and instantly say "thats whats going on". Maybe it would become more intuitive if I used it more. Anyway, good write up.

  • Charles F. Munat
    Charles F. MunatNov 22, 2024

    Your trick question goes beyond simple currying to add recursion.

    add(1) returns a function that takes a single argument, call this addOne. LIke this:

    const addOne = add(1) = (b) => b ? add(1 + b) : 1;
    
    Enter fullscreen mode Exit fullscreen mode

    This returns a closure where a is assigned 1.

    add(1)(2) is equivalent to addOne(2) where 2 is the b argument. As b exists and is not 0, this returns the output of add(1 + 2) read add(3). This makes 3 the a in a new closure, so the function it returns could be called addThree.

    const addThree = addOne(2) = add(1 + 2) = add(3) = (b) => b ? add(3 + b) : 3
    
    Enter fullscreen mode Exit fullscreen mode

    add(1)(2)(3) then is equivalent to addThree(3) which has a === 3 from the closure returned earlier and b == 3 from the argument. So again we recurse, returning add(3 + 3) or addSix.

    const addSix = addThree(3) = add(3 + 3) = add(6) = (b) => b ? add(6 + b) : 6
    
    Enter fullscreen mode Exit fullscreen mode

    So add(1)(2)(3)(4) is addSix(4) where b === 4 hence it returns add(6 + 4) which we can call addTen.

    const addTen = addSix(4) = add(6 + 4) = add(10) =
      (b) => b ? add(10 + b) : 10
    
    Enter fullscreen mode Exit fullscreen mode

    Finally add(1)(2)(3)(4)() calls addTen() with no arguments, which halts the recursion and just returns the a value (the sum) from the closure, which is 10.

    addTen() // returns 10 as `b` is undefined hence
             // `b ? (add(10 + b) : 10` returns `10`
    
    Enter fullscreen mode Exit fullscreen mode

    We can see this more clearly like this:

    const addOne = add(1)
    const addThree = addOne(2)
    const addSix = addThree(3)
    const addTen = addSix(4)
    
    addTen() // returns 10
    
    Enter fullscreen mode Exit fullscreen mode

    Easy peasy – if you understand currying, closures, and recursion.

    • Charles F. Munat
      Charles F. MunatNov 22, 2024

      P.S. Your article doesn't really explore why currying is so useful (which is why ALL functions in Haskell are curried). Why would I need an addThree function?

      The most obvious answer is the use of pipe or compose. Pipe is easier, so here's an example assuming curried arithmetic functions:

      const doTheMath = pipe(add(3), divideBy(2), multiplyBy(10), subtract(25))
      
      doTheMath(21)
      
      // 21 + 3 => 24
      // 24 / 2 => 12
      // 12 * 10 => 120
      // 120 - 25 => 95
      
      returns 95
      
      Enter fullscreen mode Exit fullscreen mode

      Note, all functions passed to pipe (except the first one) must be unary, i.e., take only one parameter.

    • Jagroop Singh
      Jagroop SinghNov 23, 2024

      Wow, Nice explanation @chasm

  • ANIRUDDHA  ADAK
    ANIRUDDHA ADAKNov 23, 2024

    Absolutely incredible! 😻.

  • Oshan Methsara
    Oshan MethsaraNov 23, 2024

    Best Programming Codes to Sell
    Get the best programming codes — 5000+ codes to buy or download for free!

    Best Programming Solutions
    _Explore thousands of programming codes in JavaScript, Python, and PHP. Whether you're building your next web app, data analysis model, or CMS plugin, we have it all.

    5000+ codes available for you to buy or download for free! Start building today!_

    👉 bestprolanguagecodes.blogspot.com 👈

  • na.perruchot
    na.perruchotNov 24, 2024

    I call that a fonctional paradigme.

  • Hafiz Abdullah
    Hafiz Abdullah Jan 21, 2025

    Informative

Add comment