DEV Community

gunjangidwani
gunjangidwani

Posted on

Currying !!Wonder of Closures in JavaScript

*What is currying, and how do closures make it possible in JavaScript? *

Currying is hot topic in frontend interview,it is usually the next question after closure because it is an example. Recently i got hit with the INFINITE CURRYING Question. Here is full detail

⚙️ Practical Benefit of Currying:

  • Delays execution until all arguments are provided
  • Enables function reusability (partial application)

Function currying is when functions are nested. This helps us to execute partially functions if there is a requirement of waiting. Example to add two number using curring

function add() { function arg1(a) { function arg2(b) { return a+b } return arg2 } return arg1 } // this returns arg1 const addnum = add() // this takes first input and return arg2 const firstArg = add(2); // taken second input and returns the sum const final = firstArg(3) 
Enter fullscreen mode Exit fullscreen mode

✅ Clean Curried Add Example:

function add(a) { return function(b) { return a + b; }; } console.log(add(2)(3)); // Output: 5 
Enter fullscreen mode Exit fullscreen mode

Explanation:

add(2) returns a closure that remembers a = 2
That returned function takes b and adds it to a.

Now if we think the above examples are quite commom. but what about infinite curring? Below is the example of it-

Can we write a function like add(1)(2)(3)...(n) that returns the sum when we call .value() or even when coerced?

🧩 Infinite Currying:

  • You need to return a function every time, so chaining like add(1)(2)(3)... works.
  • To get the final result, you’ll use: .valueOf() or .toString() for coercion (console.log(add(1)(2)(3))) OR an explicit .value() method.
  • Use a closure to keep the running sum.
function add(a) { let sum = a; function inner(b) { if (b !== undefined) { sum += b; return inner; // keep returning the function for chaining } return sum; // fallback, if no argument is passed } inner.valueOf = function () { return sum; }; inner.toString = function () { return sum.toString(); }; return inner; } console.log(+add(1)(2)(3)); // 6 console.log(add(5)(10)(15) + 0); // 30 inner.value = () => sum; 
Enter fullscreen mode Exit fullscreen mode

📜 1.Another example by arbitrary argument counts in each call? Like:
add(1, 2)(3, 4)(5)(6) // → 21

Solution-

function sum(...initialArgs) { let storage = [...initialArgs]; function inner(...nextArgs) { storage.push(...nextArgs); return inner; } inner.valueOf = function () { return storage.reduce((a, b) => a + b, 0); }; inner.toString = function () { return this.valueOf().toString(); }; inner.value = function () { return this.valueOf(); }; return inner; } 
Enter fullscreen mode Exit fullscreen mode

📜 2. Add History Tracking (Bonus Closure Feature)

function sumWithHistory(...initialArgs) { let storage = [...initialArgs]; function inner(...nextArgs) { if (nextArgs.length === 0) { return storage.reduce((a, b) => a + b, 0); } storage.push(...nextArgs); return inner; } inner.valueOf = function () { return storage.reduce((a, b) => a + b, 0); }; inner.toString = function () { return this.valueOf().toString(); }; inner.value = function () { return this.valueOf(); }; inner.history = function () { return [...storage]; }; return inner; } const s = sumWithHistory(1)(2, 3)(4); console.log(s.value()); // 10 console.log(s.history()); // [1, 2, 3, 4] 
Enter fullscreen mode Exit fullscreen mode

we can combine these into a reusable curry utility that can handle any reducer function (e.g., sum, product, max, etc.)!

Top comments (0)