# Currying in JavaScript: Why Closures Beat `.bind()` Every Time

 You've seen the code. A function that returns a function that returns a function. You squinted at it, maybe copy pasted it into your project, and quietly moved on. Later, someone asks you to explain currying in a code review and you freeze.
 
Or maybe you've been using `.bind()` for partial application for years and it always felt a little... off. Like you were forcing a screwdriver to work as a hammer.
 
This post is the explanation you wanted the first time. By the end, these patterns won't just *work* — they'll make sense.
 
---
 
## First: What problem are we actually solving?
 
The core idea is simple: sometimes you have a function that takes multiple arguments, but you only know *some* of those arguments right now. You want to pre-fill what you know and call the rest later.
 
Think of it like a pizza order form. You always order from the same place (fixed), but the toppings change (variable). You don't want to re-enter the restaurant details every time. You want a *specialized version* of `order()` that already knows where it's going.
 
That's partial application. Currying takes it further: it transforms a function so each argument gets its own call — `f(a, b, c)` becomes `f(a)(b)(c)`.
 
There are two main ways to do this in JavaScript: `.bind()` and closures. They're not the same, and one is vastly more powerful.
 
---
 
## Approach 1: `.bind()` — Quick but limited
 
`.bind()` creates a new function with some arguments pre-filled from the left.
 
```js
function add(a, b, c) {
  return a + b + c;
}
 
const add5 = add.bind(null, 5);
console.log(add5(10, 20)); // 35
 
const add5and10 = add.bind(null, 5, 10);
console.log(add5and10(20)); // 35
```
 
Clean. Readable. Gets the job done for fixed-arity functions (functions with a known, fixed number of arguments).
 
But notice that `null` as the first argument. That's the `this` context — bind was *designed* to rebind `this`, and partial application is kind of a side effect of that design. You're using a `this`-binding tool for an argument-filling job.
 
That conceptual mismatch has practical consequences:
 
- **Fixed argument count only.** `.bind()` has no mechanism to accumulate arguments dynamically. You pre-fill from the left and that's it.
- **No dynamic currying.** You can't build a general purpose curry utility around `.bind()`.
- **Changes `this`.** Sometimes you want that. Often you don't — but now you have to think about it.

![failed miserably](https://media1.tenor.com/m/7wznJFMhTUcAAAAC/toomuch-fail.gif align='center')
 
---
 
## Approach 2: Closures — The real foundation
 
A closure is just a function that *remembers* the variables from the scope it was defined in, even after that outer scope has returned.
 
That "memory" is exactly what makes currying work.
 
```js
function add(a) {
  return function(b) {
    return function(c) {
      return a + b + c; // a and b are remembered via closure
    };
  };
}
 
console.log(add(1)(2)(3)); // 6
```
 
Each inner function has access to the arguments passed to every outer function. `a` doesn't disappear when `add(1)` returns — the inner function holds a reference to it.
 
Think of it like a backpack. Every time you go one level deeper, you hand the next function a backpack with all the previous values. It carries them until you're ready to use them.
 
---
 
## Where closures really shine: variable argument counts
 
Here's where `.bind()` simply can't compete. What if you don't know how many arguments you'll get?
 
```js
function sum(a) {
  return function(b) {
    if (b === undefined) {
      return a; // done collecting — return the total
    }
    return sum(a + b); // keep accumulating
  };
}
 
console.log(sum(1)(2)(3)(4)()); // 10
```
 
Walk through this:
- `sum(1)` returns a function, closing over `a = 1`
- `sum(1)(2)` calls that function with `b = 2`, which returns `sum(3)`
- `sum(3)(3)` returns `sum(6)`
- `sum(6)(4)` returns `sum(10)`
- `sum(10)()` — `b` is `undefined`, so we return `10`
The closure keeps state alive between calls. No class, no external variable, no mutation. Just functions remembering their past.
 
![snowball effect](https://media2.giphy.com/media/v1.Y2lkPTc5MGI3NjExbGpmdDdrNmxkOHA4bzN2cnAwYTMwbzR3aTMyOWdjaDAybTJteWx2eSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/4HGfB0gSHsebJqxkN0/giphy.gif align='center')
 
---
 
## A practical curry utility
 
The real payoff: you can write a general-purpose `curry()` function that works with *any* fixed-arity function.
 
```js
function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      // We have all the arguments fn expects — call it
      return fn(...args);
    }
 
    // Not enough arguments yet — return a function that collects more
    return function(...next) {
      return curried(...args, ...next);
    };
  };
}
```
 
The key insight: `fn.length` tells you how many parameters `fn` expects. The closure (`curried`) accumulates arguments across calls until that threshold is met.
 
```js
function multiply(a, b, c) {
  return a * b * c;
}
 
const curriedMul = curry(multiply);
 
console.log(curriedMul(2)(3)(4));   // 24
console.log(curriedMul(2, 3)(4));   // 24 — batch arguments work too
console.log(curriedMul(2)(3, 4));   // 24
```
 
All three produce `24`. The callers get to decide how they group the arguments — the curry utility doesn't care.
 
This flexibility is impossible with `.bind()`. You can't batch arguments and you can't build this kind of accumulation logic around it.
 
---
 
## A quick terminology check: currying vs partial application
 
People use these terms interchangeably, which causes endless confusion. They're related but distinct:
 
**Partial application** — pre-filling *some* arguments of a function, getting back a function that takes the rest.
 
```js
// Partial application
const add10 = (b, c) => add(10, b, c);
// or with bind:
const add10 = add.bind(null, 10);
```
 
**Currying** — transforming `f(a, b, c)` into `f(a)(b)(c)`. Each call takes exactly one argument and returns a new function.
 
Closures are the foundation of *real* currying in JavaScript. `.bind()` can do partial application, but it can't do currying in the general sense.
 
---
 
## When `.bind()` still wins
 
To be fair: there's one thing `.bind()` does that closures don't automatically replicate — **permanently rebinding `this`**.
 
```js
const obj = {
  x: 10,
  getX() {
    return this.x;
  }
};
 
const fn = obj.getX;
console.log(fn());           // undefined — lost `this`
 
const bound = obj.getX.bind(obj);
console.log(bound());        // 10 — this is permanently locked
```
 
A closure won't save you here without explicitly capturing the reference:
 
```js
const bound = () => obj.getX(); // works, but different semantics
```
 
Arrow functions preserve the *lexical* `this` (the `this` from where they're defined), which handles some use cases — but it's not the same as `.bind()`'s hard binding.
 
So `.bind()` has a rightful home. It's just a narrow one.
 
![tricky job](https://media1.tenor.com/m/EU8GKqBgluYAAAAd/this-is-a-really-tricky-job-stoat.gif align='center')
---
 
## The practical cheat sheet
 
**Use closures when:**
- You need real currying (chained single-argument calls)
- You need flexible partial application
- You're doing functional programming (pipelines, composition)
- You need to accumulate a variable number of arguments
- You're writing utility functions like `curry()`, `compose()`, or `memoize()`
**Use `.bind()` when:**
- You need to permanently fix `this` for a callback
- You want a quick, one-off partial application for a simple fixed-arity function
- You're passing a method as a callback and need it to keep its context
---
 
## Three things to take away
 
1. **Closures are how currying actually works in JavaScript.** Each inner function holds a reference to outer variables — that's the "memory" that makes argument accumulation possible.
2. **`.bind()` is a `this`-binding tool that happens to support partial application.** It's useful for that exact scenario, but it can't build flexible curry utilities or handle dynamic argument counts.
3. **Currying and partial application are different things.** Partial application pre-fills some args. Currying transforms a multi-argument function into a chain of single-argument functions. Closures can do both; `.bind()` can only do partial application.
Next time you see `fn => arg => anotherArg => ...`, you'll know exactly what's happening: a chain of closures, each one carrying the accumulated context forward. No magic — just functions remembering their past.
 
