
When you’re first learning JavaScript, terms like “closures” may make the language appear mystical and hard to understand. But some of these terms are just sugary concoctions that give fanciful names to very simple concepts. If you’ve spent just a few minutes tinkering with JavaScript, you’ve probably used closures without knowing it. That’s because the JavaScript language depends on closures to create programs that are concise and efficient. By the end of this tutorial, you will gain a full understanding of closures.
What is a closure?
In order to really understand closures, it is helpful to know how scope works. We covered scope in a previous article, so we’ll quote it here:
[I]f you declare a function within another function, you create what’s called a scope chain. The outer parent cannot see the variables of its child(ren), but the child can see the variables of its parent(s). Confused? Think of a Matryoshka doll. Now imagine if these dolls were given life(scary thought). An outer doll wouldn’t be able to see the gruesome innards of an inner doll. The inner doll can see everything. Now that’s scope.
We can conclude that the inner function has three scope chains. The first chain allows the inner function to access its own variables. The second allows it to access the variables and parameters of the outer function. And the third allows it to access the global variables. Every time we add a function, we’re adding a new link to the chain.
By defining a function within another function, we create a closure. Closures themselves can also take on the role of outer functions. Take this somewhat practical example of multiple closures:
In this example, we have two closures. combineName()
is a closure to the outer function of sayMyName()
. getRandomInt()
serves as both a closure to combineName()
and sayMyName()
. What this means is that combineName()
has three scope chains while getRandomInt()
has four scope chains. Every time we create a closure, one link is added to the scope chain. So, getRandomInt()
can access the variables of combineName()
and sayMyName()
.
Side Note: As you can see from the example, we were able to “borrow” the parameters from sayMyName and use them in our first closure, all thanks to the trickle down effect scope chains have, which, *ahem*, is far more reliable than trickle down economics. One point to note, however, is that you cannot call an outer function’s arguments object from within a closure.
Closures In Depth
We’ve briefly outlined what closures are. Now let’s go through some use cases and explore the deepest depths of closures.
Closures are basically the walking dead. When a function returns, the idea is that all of the variables within that function should be non existent. Yet, closures still have access to any variables in their scope chains.
Here’s an example:
The reason why we can still access the name of this “zombie” isn’t due to any sci-fi magic, it’s because closures don’t store value. Values are static. Instead, they store references to values in their scope chains. The amazing thing is that if you were to change the value of a variable up in the scope chain before returning the closure, the same value used within the closure will then update. This phenomenon is called state, which is the backbone of programming. We want to be able to create functions whose inner data lives on through the lifetime of our apps. When a user inputs data, we want that data to be updated.
We’ll show an example of how we can use closures to create a modular pattern by modifying our above code:
What we’ve created is an anonymous closure by enclosing our first function within parenthesis.
(function(){…})();
Side Note: Anonymous closures or Instantly Invoked Function Expressions execute immediately and allow us to maintain state and manage privacy. Unlike other object oriented languages like C++ or Ruby, JavaScript is yet to implement any native private methods. There are several JavaScript developers who, after tasting ES6’s new class keyword, are pining for private syntax. For now, we have to make do with closures to code private/public data.
Any function or variable within our anonymous closure is considered private. The closures within the anonymous wrapper after the return
statement have access to the private functions, but users cannot access the private functions outside of the module. The private data is effectively closed off by our anonymous closure, as most private things are.
Conclusion
Closures are a prime example of the flexibility of JavaScript’s functions. In just a few examples we’ve set functions to variables, returned functions, called anonymous functions, have used functions as keys, not to mention the fact that we self-invoked a function. All of these functional, acrobatic tricks all have terms that apply to them. Just remember that closures are those functions that are defined within another function.
Here are some great resources if you want to continue on with your journey in mastering closures and many more JavaScript quirks:
Code in Peace,
Raji Ayinla| Technical Writing Intern @ CodeSmith Staffing