FrontendPrep
Menu
Topics
Questions
Guides
Challenges
Soon
Back to JavaScript Questions
javascriptMedium

JavaScript: Currying and Partial Application

Understand currying and partial application in JavaScript. Learn how they differ, how closures enable them, and how to write a function that performs infinite currying.

JavaScript: Currying and Partial Application

A favorite advanced functional JavaScript question is:

What is currying, and how does it differ from partial application? How do closures support these patterns, and how would you implement a function to handle infinite currying?

Both currying and partial application are functional programming patterns that allow you to transform function signatures. They are highly valued in interviews because they test your mastery of closures, recursion, and argument collection.


1. Currying vs. Partial Application

Although often used interchangeably, they represent distinct mathematical transformations:

  • Currying: A process that translates a function of multiple arguments (f(a, b, c)) into a chain of nested functions, each accepting exactly one argument (f(a)(b)(c)).
  • Partial Application: A process that binds some arguments of a function immediately, returning a new function that accepts the remaining arguments (f(a, b)(c)).
       Original Function: sum(a, b, c)  // Needs 3 arguments
 
       Currying:
       sum(1)(2)(3) ──► Returns nested functions of arity 1 until final value
 
       Partial Application:
       const addFive = sum.bind(null, 2, 3);
       addFive(4)   ──► Pre-binds 2 and 3, returns function of arity 1

2. Implementing a Standard Curry Helper

In JavaScript, you can implement a generic curry wrapper that converts a standard function into a curried version by checking the function's expected number of arguments (length property):

function curry(targetFn) {
  return function curried(...args) {
    // If we have received all expected arguments, execute targetFn
    if (args.length >= targetFn.length) {
      return targetFn.apply(this, args);
    }
    // Otherwise, return a new wrapper function to collect more arguments
    return function (...nextArgs) {
      return curried.apply(this, [...args, ...nextArgs]);
    };
  };
}
 
// Verification
const multiply = (a, b, c) => a * b * c;
const curriedMultiply = curry(multiply);
 
console.log(curriedMultiply(2)(3)(4)); // Outputs: 24
console.log(curriedMultiply(2, 3)(4)); // Outputs: 24 (Hybrid signature allowed)

3. Implementing Infinite Currying

A common variation of this question is writing a function that supports infinite currying, like add(1)(2)(3)...().

To achieve this, the helper must repeatedly return a function that accumulates values until it is called with no arguments (or coercion is requested):

Signature A: Terminated by empty execution ()

function add(x) {
  return function (y) {
    if (y !== undefined) {
      return add(x + y); // Keep accumulating
    }
    return x; // Return final result when executed with ()
  };
}
 
console.log(add(1)(2)(3)(4)()); // Outputs: 10

Signature B: Implicit Value Coercion (Advanced)

If you want the function to be evaluated directly without an ending empty call (e.g. add(1)(2)(3) returning 6), you must override toString or valueOf:

function addCoerce(x) {
  const sumFn = (y) => addCoerce(x + y);
  
  // Custom coercion behavior
  sumFn.valueOf = () => x;
  sumFn.toString = () => String(x);
 
  return sumFn;
}
 
const sumVal = addCoerce(1)(2)(3);
console.log(+sumVal); // Outputs: 6 (coerced using unary plus)

Senior-Level Interview Answer

Currying is a functional transformation that splits a multi-argument function of arity $N$ into a series of unary functions that resolve on the $N$-th invocation. Partial application fixes a subset of arguments ahead of execution, yielding a function that accepts the remaining parameters. Both patterns rely on JavaScript closures, which retain access to variables in their lexical environment after outer functions return. A custom curry wrapper evaluates the accumulated arguments length against the expected target function length. If the argument quota is met, it executes the target function; otherwise, it returns a closure that merges existing arguments with incoming ones via recursion.


Common Interview Mistakes

❌ Confusing Currying with Partial Application

Saying that currying means "calling a function with fewer arguments than it expects." That describes partial application. Currying specifically refers to creating a strict chain of single-argument functions.

❌ Forgetting context binding

When implementing curried functions, failing to pass down the correct this context (e.g., omitting .apply(this, ...)). If the curried function is a method on an object, failing to propagate this will break references to other internal properties on that object.


Key Takeaways

  • Closure Scope: Both patterns rely on closures to store parameters in memory across multiple execution steps.
  • Strict Currying: Splitting $N$-argument calls into chains of single-argument functions (f(a)(b)(c)).
  • Arity Validation: Auto-currying compares argument collection count against function signature length metadata.
  • Partial Binding: Freezing a set of arguments immediately to simplify downstream invocation signatures.
  • Infinite Accumulation: Using recursive closures to build math functions that accumulate arguments until terminated.

Share this Resource

Help other developers level up by sharing this study guide.

More Technical Questions

Expand your mastery. Deep dive into other frontend interview challenges in this category.