Closures

As you know, functions can be nested within other functions

You’ve recently written code like this:

const evens = (numbers) => {
  return numbers.filter((n) => n % 2 === 0);
}

The expression (n) => n % 2 === 0 is an anonymous function defined within the body of the function evens.

That could also be written like this, giving the nested function a name.

const evens = (numbers) => {

  const isEven = (n) => n % 2 === 0;

  return numbers.filter(isEven);
};

isEven is a local variable in the function evens; it only exists within the scope of the body of evens.

In this case it might make more sense to move isEven outside of evens.

const isEven = (n) => n % 2 === 0;

const evens = (numbers) => {
  return numbers.filter(isEven);
};

Since isEven’s behavior depends only on the argument passed in to it, this works fine.

But suppose we wanted to write a function that returns the elements of numbers that divisible by a specified number.

const divisibleBy = (numbers, divisor) => {

  const hasDivisor = (n) => ... // something here

  return numbers.filter(hasDivisor);
};

In this case, we need a function to pass to filter that a) only takes one argument and b) can also refer to the variable divisor.

We can write this.

const divisibleBy = (numbers, divisor) => {

  const hasDivisor = (n) => n % divisor === 0;

  return numbers.filter(hasDivisor);
};

Each time we call divisibleBy a new hasDivisor function is defined that checks its argument n against the particular divisor passed to divisibleBy.

We can also use an anonymous function

const divisibleBy = (numbers, divisor) => {
  return numbers.filter((n) => n % divisor === 0);
};

This does exactly the same thing without giving the function a name.

This kind of function is called a “closure”.

It “closes over” a variable that is defined in the environment where the function is defined.

Can we break out hasDivisor?

We can’t move hasDivisor out of divisibleBy the way we did with isEven because it needs to reference divisor which only exists within divisibleBy.

But we can do this

Define a higher-order-function that returns a function:

const hasDivisor = (divisor) => {
  return (n) => n % divisor === 0;
}

Each time we call hasDivisor it creates a new closure that closes over the variable naming the specific value we passed in.

It may seem weird …

… that we can return that function since the variable divisor only exists within hasDivisor and we’re returning from that function?

Turns out, it’s totally cool to do this. And quite handy.

Could use it to define functions:

const isEven = hasDivisor(2);

const isRoundNumber = hasDivisor(10);

Can also use it in divisibleBy

const divisibleBy = (numbers, divisor) => {
  return numbers.filter(hasDivisor(divisor));
};

Closures close over variables, not values

const counter = (start) => {
  return () => start++;
}

const c1 = counter(100);
const c2 = counter(100);

c1() ⟹ 100
c2() ⟹ 101 // The value of the variable has changed
c2() ⟹ 100 // Each function has its own closed-over variable

The closures created by counter don’t just capture the initial value of start; they actually keep the variable alive.

What do you suppose this does?

const complement = (f) => {
  return (x) => !f(x);
}

What must f be?

What kind of value is (x) => !f(x)?

What? Why?

const isEven = (n) => n % 2 === 0;

const isOdd = complement(isEven);