Compile Ready
Module 11 · Advanced JavaScript

Currying

Advanced13m read22m practice35m total
CurryingFunctional ProgrammingClosuresMachine Coding

Introduction

Currying transforms a function that expects multiple arguments into a chain of functions that can receive those arguments gradually. sum(a, b, c) becomes something that can be called as sum(1)(2)(3), sum(1, 2)(3), or sum(1)(2, 3) depending on the implementation.

In interviews, currying is less about clever syntax and more about closures, arity, partial application, argument collection, and preserving this when forwarding a final call.

Why This Matters

Currying appears in machine-coding rounds because it combines rest arguments, closures, recursion, Function.length, and apply. It also appears in production through validators, logging helpers, Redux-style middleware, and function composition utilities.

Theory

Core idea

A normal function consumes all required inputs in one call. A curried function keeps returning another function until it has collected enough arguments to call the original function. The collected arguments live inside closures.

Arity and completion

Most interview implementations use fn.length, the number of declared parameters before the first default or rest parameter, as the target arity. When collected arguments are at least that count, call the original function. Otherwise return another collector.

Mixed partial calls

A strong curry accepts more than one argument per step. Each new call concatenates the old arguments with the new arguments. That supports curried(1)(2)(3), curried(1, 2)(3), and curried(1)(2, 3) with one implementation.

Pitfalls

Forgetting to concatenate arguments, losing this, and relying blindly on fn.length for functions with default or rest parameters are the common bugs.

Visual Diagrams

Argument collection across calls
curried(1) stores [1]
   |
returns a collector
   |
collector(2, 3) concatenates [1] + [2, 3]
   |
collected enough arguments
   |
call original function

Each partial call closes over the arguments collected so far.

Code Examples

A curry helper with mixed partial application

The helper concatenates arguments at every step and forwards the final call with apply.

Loading…

Playground

Loading editor…
Console

Press Run to execute the code and see output here.

Output Prediction

Predict the output #1

javascript
1function curry(fn) {
2 return function curried() {
3 var args = Array.prototype.slice.call(arguments);
4 if (args.length >= fn.length) {
5 return fn.apply(this, args);
6 }
7 return function () {
8 var more = Array.prototype.slice.call(arguments);
9 return curried.apply(this, args.concat(more));
10 };
11 };
12}
13
14function join(a, b, c) {
15 return a + '-' + b + '-' + c;
16}
17
18var curried = curry(join);
19console.log(curried('A')('B')('C'));
20console.log(curried('A', 'B')('C'));
21console.log(curried('A')('B', 'C'));

Coding Exercises

Implement curry with mixed partial calls

Medium

Write curry(fn) so the returned function can be called with any grouping of arguments until fn.length arguments have been collected. Preserve the call-time this value when invoking the original function.

Interview Questions

1What is currying, and how is it different from partial application?

Currying transforms a multi-argument function into staged calls that gather arguments over time. Partial application fixes some arguments and returns a function for the rest. A curry helper often enables partial application, but the concepts are not identical.

Asked at:MetaAmazonMicrosoft

Follow-ups

  • How would you support placeholders?
  • What happens with default parameters?
2Why does a curry implementation use closures?

Each returned function must remember the arguments collected by previous calls. Closures keep that private state alive until enough arguments have been gathered.

Quiz

1. When should a basic curry helper call the original function?

Summary

  • Currying collects arguments across multiple calls using closures.
  • A robust helper supports mixed groups by concatenating arguments.
  • `fn.length` is the common arity signal, with caveats for default and rest parameters.
  • Use `apply` when forwarding the final call to avoid losing `this`.

Cheat Sheet

Currying: turn fn(a, b, c) into staged calls.

Completion: call original when collected args >= fn.length.

Tools: closures, argument arrays, concatenation, apply.

Pitfall: default and rest parameters change what fn.length reports.