Currying and Closure

Consider this function:

function makeSundae(base, topping) {
  return `Here is your ${base} ice cream with ${topping}!`;
}

const sundae = makeSundae("vanilla", "hot fudge");
console.log(sundae);

Functions are values. Therefore, a function can return a function! This feature can be used in interesting ways!

function makeSundae(base) {
  return function (topping) {
    return `Here is your ${base} ice cream with ${topping}!`;
  }
}

const vanillaSundae = makeSundae("vanilla");
const chocolateSundae = makeSundae("chocolate");

console.log(chocolateSundae("hot fudge"));
console.log(vanillaSundae("chocolate syrup"));

What we have done with makeSundae function is called currying in functional programming.

Currying is converting a function that takes $n$ arguments to return a chain of functions that each takes one argument.

Here is a more practical example

function makeLog(base) {
  return function(value) {
    return Math.log(value) / Math.log(base);
  }
}

const log10 = makeLog(10);
const log2 = makeLog(2);

console.log(log10(100));
console.log(log2(8));

Notice the returned inner function retains access to the variables defined in the parent function even after the parent is out of scope. (Since the parent function has returned, our expectation demands that its local variables no longer exist. But, they do still exist!) This feature, in functional programming, is called closure.

Closure is when a function remembers and continues to access variables from outside of its scope.

function counter(step = 1) {
  let count = 0;
  return function increaseCount () {
    count += step;
    return count;
  }
}

const incBy1 = counter();
const incBy10 = counter(10);


console.log(incBy1());
console.log(incBy1());

console.log(incBy10());
console.log(incBy10());
Resources