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)