What the Banana is a Closure

I’ve spent the last few months (going on a year now) learning JavaScript, and during that time I’ve grappled with closures in a perpetual battle to acquire understanding through brute force. And yet, the concept of a closure, like many aspects of JavaScript, is not as confusing as it first appears.

To begin, a basic definition a closure: a closure is a function that retains access to the lexical environment in which is was created after the initial function environment has returned.

Don’t worry about that definition, because on its own, if you did not know what a closure is, that would not help you. Here’s an example of a basic function which takes advantage of closure:

var closureMaker = function(){
  var privateVariableArray = [];

  return {
    pushToPrivateVariable: function(value){
      privateVariableArray.push(value);
    },
    popPrivateVariable: function(){
      return privateVariableArray.pop();
    }
  }
}

The basic function closureMaker contains an array called privateVariableArray. Nothing fancy so far. Next, closureMaker returns an object with two methods. Each of these methods interacts with the privateVariableArray. This code in action might look like this:

var newFunc = closureMaker();
//remember, closureMaker returns an object with two methods.
//each of these calls pushs to the privateVariableArray.
newFunc.pushToPrivateVariable(1);
newFunc.pushToPrivateVariable(2);
newFunc.pushToPrivateVariable(3);
//now, we return the last item from the array, 3.
newFunc.popPrivateVariable();

The above doesn’t appear mysterious, and that’s because it isn’t. We are simply pushing items to an array, and then removing them. Basic JavaScript Arrays 101. The difference here is that the array we are interacting with is in a function object which has already returned, and yet, we are able to interact with it outside of the function object. If that doesn’t sound strange, consider another function, which does not make use of a closure.

var boringFunc = function(){
  var localVar = 19;
}
console.log(localVar);

What happens when the console tries to log the localVar? An error pops up notifying that localVar is not defined. I defined it inside the function object scope of boringFunc, but when I called console.log(localVar) outside the function objects scope, and since I did not have access to the localVar, I received an expected error. Outside of the function, I have no way to interact with localVar.

If I attempted to log privateVariableArray, the same error will pop up since the variable does not exist in the global scope. In this regard, localVar and privateVariableArray are the same. The difference is that we can interact with privateVariableArray via newFunc.pushToPrivateVariable and newFunc.popPrivateVariable. However, the key here is that there is no other way to interact with privateVariableArray outside of those methods. The fact that we can interact with the variable at all is made possible by closure. ##Why Use Closures and Private Variables Closures in JavaScript are so powerful because they allow you to create a private variable. But if you don’t know what a private variable is, the ability to create one won’t matter. A private variable is a variable that can only be accessed through a provided interface. In the example above, the private variable(privateVariableArray) can only be accessed through the functions we returned (the push and pop methods.) Those two methods we returned are referred to as interfaces, since they are the only interface available to access the private variable.

If you’re learning what a closure is for the first time, the value of a private variable might not be apparent, especially since many of the problems beginners and intermediates encounter don’t utilize. Here are a few reasons why private variables are so useful:

  • Most modern javascript programs attempt to limit the number of global variables that exist. Private variables offer a workaround. If you’re curious about the problems created by global variables, I recommend checking out Stack Exchange for a brief overview, but in essence, the problem is that global variables can cause issues with bug testing in addition to a few other pesky issues.

  • Most programs are not created by a single person, but rather by a team. When you create a private variable and set up interfaces, the team can simple use those interfaces to do what you intended with the private variable without having to dig into the code you wrote, saving them time, and maintaining cleaner code.

  • Similarly, if you create an API, you will likely want to limit the ways that other developers or users interact with your program, not so much for security reasons (although that is a factor), but also for usability concerns. For instance, say your code is 100 lines long but the developer using your code only needs to know what it does, not necessarily how it does it. In this scenario, providing those interfaces to the private variables reduces the amount of time the developer has to invest in learning how to use your tool.

How to Get the Hang of Closures

First off, you should read around the internet at places like Javascript is Sexy, the venerable Stack Overflow, and of course, always at Mozilla Developer Network. After reading through each of these resources, and working through the provided examples, you’ll develop a sense of what closures are and how to utilize this feature. After that, it’s time to put your knowledge to the test. For myself, closures didn’t click as a concept until I implemented them in a small project. By doing so, I gained a sense of their value in a concrete way (rather than the abstractions provided by examples such as the ones I’ve given, or even the other resources have given). In essence, like most aspects of programming, true learning happens by putting difficult concepts into action. Soon, the idea of a closures, heretofore this vague and difficult idea to wrap your brain parts around, will become second nature, another tool in your belt, almost as easy as that for loop which you can implement in your sleep.

Written on January 18, 2016