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);

The fact functions are values enable us to make a function that returns a function. This 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 is called currying in functional programming.

Currying is converting a function that takes \(n\) arguments to return a chain of functions that each take one argument.

Here is a more useful 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, 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());

For more examples, refer the examples on MDN web docs, Closure.

If interested, freeCodeCamp has a good article "JavaScript Closures Explained by Mailing a Package".