Hacker News new | ask | show | jobs
by tel 4048 days ago
Closures are one implementation of functions. In a language which also has mutable variables, closures create a special kind of private variable behavior.

You're used to thinking of functions which act on things passed into them via their parameters. For instance:

    function apply(f, x) { return f(x); }
My example, apply, is a bit unique in that it only uses things passed in through the parameters. More normally, you might also use names of things available in the scope when you define the function, for instance:

    function log(x) { console.log(x); }
In this example, the behavior of add depends not only on the parameter x but also the fact that console.log is defined ambiently.

What a closure refers to is the fact that functions can capture names which are only ever available locally thus hiding a reference inside of them. A simple example might be:

    function makeExample() {
      var exampleText = "Hello world";
      return function printer() {
        console.log(exampleText);
      }
    }

    var myPrinter = makeExample();
    printer();
    // Hello world
In this case, the variable `exampleText` is clearly being captured in the definition of `printer`, but since `exampleText` is only defined in the scope of `makeExample`, we have no way of accessing it. The function stored at `myPrinter` has closed over its own copy of `exampleText` can uses it internally in a way we cannot access.

So finally we can turn to the more interesting examples where we combine this closure/capture property with mutability. The canonical example is the counter:

    function makeCounter() {
      var count = 0;
      return {
        get: function get() { return count; },
        inc: function inc() { count += 1; },
        dec: function dec() { count -= 1; }
      }
    }

    var myCounter = makeCounter();
    var get = myCounter.get;
    var inc = myCounter.inc;
    var dec = myCounter.dec;

    assert(get() === 0);
    inc();
    assert(get() === 1);
    dec();
    assert(get() === 0);
Here, `makeCounter` returns a struct of functions which have all independently captured a reference to the same hidden variable `count`. While I return them all together in an object, I also destructure that object to stress that there's nothing funny going on—the three functions have to be created together to capture the same `count` variable, but afterward they can be separated far and wide.

Since all three functions reference the same hidden variable state they can manipulate it together. This is the magic of variable capture under mutable state: closures.

---

So what's the point?

Well, we've essentially created a private mutable variable on a home-grown object system. There is no way for someone to access the secret `count` reference except via the get/inc/dec functions which have closed over it. This can be very valuable for data encapsulation.

To skip to the punch, Javascript only has a reasonable module system because of closures. If you're familiar with the IIFE-based modules of Javascript they go a little like this

    exports = {};

    (function(exports) {

      var count = 0;

      function inc() { count += 1 };
      function dec() { count -= 1 };

      // With only this function and not `get` exported we can never
      // actually view the value of count. This can be very useful
      // for implementation hiding and building a minimal API.
      function isEven() { return count % 2 == 0 };

      exports = { inc: inc, dec: dec, isEven: isEven };
  
    })(exports)
Here we see that the IIFE creates a private, local scope where names like `count` can be created and closed over by exported functions like `inc`, `dec`, and `isEven`. This public/private API building is the core of module creation and, ultimately, it rests upon the creation of closures.