Lesson 16 of 80
Turning a function that takes several arguments into a chain of functions that each take one — built entirely out of closures returning closures.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 2
In `function add(a) { return b => a + b; }`, what mechanism lets the returned function still access `a` after `add` has already returned?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
Currying transforms f(a, b, c) into f(a)(b)(c) — a chain of one-argument functions, where each one remembers the arguments already given and waits for the next.
function add(a) {
return function (b) {
return function (c) {
return a + b + c; // closes over a, b, and c
};
};
}
add(1)(2)(3); // 6
const addFive = add(5); // partially applied — a is locked in at 5
addFive(2)(3); // 10
Each returned function is a closure over the arguments collected so far. That's the whole mechanism — currying isn't a special language feature, it's an ordinary pattern of functions returning functions, each one remembering what came before.
add(1)(2)(3) — a chain of calls, not one call with three arguments.
debounce or a counter factory.addFive above is a reusable, specialized function — currying is how you turn one general function into a family of specific ones without rewriting anything.const fetchWithBase = (base) => (path) => fetch(base + path) — fetchWithBase("/api") gives you a ready-to-reuse function that already knows its base URL."Write a curry function that works for any function's arity" is a common exercise that tests closures, recursion, and Function.prototype.length all at once — it's a good proxy for whether closures actually clicked, not just whether you can define the term.