All JavaScript Functions are Closures

Mayank
|
June 27, 2021

JavaScript closure is one of the most dreaded topics to talk about. Quite a few readers won't even bother to read on but hey! hang in there and we will keep things simple. We shall make them look real simple to be more precise. To explain what closures are, I won't go with the classic ubiquitous example of a silly function within another function. If you're interested in a simple example that involves currying, you may try out this codepen. Well, closures play a very obvious role when implementing event handlers (DOM Level 2). Lets talk with an example, shall we?

Try this out on codepen

There's nothing much to the code shown above, its as simple as a function that takes in an integer and sets event listeners on two different buttons. The first event listener calls a function (callback) when the first button is clicked. The callback function in turn increments the counter and shows it in an alert box. The second event handler does nothing different apart from the fact that its callback function decrements the same counter. Do we understand that even after the function setClickHandler has finished execution (offboarded from the execution stack with all its variables and arguments), the two event listeners are actively listening for a click on the respective buttons? Well, that's how event listeners work, right? You set them up once and they stay there for you unless you call "removeEventListener" on the node. There's another interesting thing to observe in the small code snippet. When the function "setClickHandler" has already left the call stack (no arguments and local variables in memory anymore), why do the callback functions not throw a "ReferenceError" when trying to access the argument "counter" which effectively lies in the lexical scope of "setClickHandler" ? Well, if you want to attribute this to the scope chain, you won't be completely wrong but then when I ask you how does something up in the scope chain remain active in memory after the owner function has offboarded the execution stack? That's when you need to say CLOSURES.

What is a closure?

Lets try to gain some clarity on what we discussed so far. The MDN says a function along with references to its surrounding scopes is a closure for that function. Well, won't you then protest that literally every function in JavaScript by default gets access to everything in its respective lexical (surrounding) scope? If that's true then every function has to have a closure as soon as its created. Bingo! guess who is correct again? Remember, that's not true for functions created with the Function constructor. We usually tend to ignore a function's ability to fom closures when the function finishes its execution well within its lexical scope. What if the same function gets returned from its lexical scope and is refrenced somewhere else later in time? The function will still have access to the references (memory location of variables and functions) in its lexical scope as it would even if it were not returned. Wait! how? Didn't the scope chain die when the outer function finished execution? Infact, it did! but before it died, right when the inner function was being returned, the scope chain was saved as a property ( or an internal slot as ECMAScript quotes ) of the inner function itself. The specification calls it [[Environent]] however Google Chrome uses something like ( [[Scopes]]: { closure } ). It seems chrome did this back in time following the old specification from 2011. Just to mention, Firefox and IE don't even show a function's inner slot like chrome does. Alright, so this saved scope chain is nothing but Closure. That's how an inner function closes over the references in its surrounding scope.

If you try to inspect such a function's execution in devtools, you shall notice that as soon as the function is pushed on the top of the execution stack, its closure shows up in the scope chain as if the function carried it throughout. If you're 5, a closure is a function who took notes ( [[Environent]] ) to remember what has been taught in the school, outside the school.

Detect a Closure

If you really want to visualize this, the easiest way is to use an online visualizer. I will keep it simple and use chrome devtools instead.

Inner function "you" returned from the outer funtion "school"

It's not necessary that the inner function be returned to form a closure

Chrome does not show the inner function in the Local scope

Conclusion

Well, now you know how closures are formed. The last example can be a bit confusing. So to clarify, since Chrome does not show the inner function in the outer function's local scope, it does not mean that it doesn't exist (You can see that on Firebox). Chrome probably lists the function only when it has been invoked, stored or returned. Similarly, every function when created forms a closure with its surrounding scope but we only care about closures when the function escapes its lexical scope to execute at some point later in time after its surrounding function is dead. In the end, it doesn't matter much whether you say all JavaScript functions are closures or all JavaScript functions have closures. Here's an interesting codepen that demonstrates function currying, a good practical use-case of closures.I would also recommend reading the performance considerations on MDN.

written by
Mayank
Web Technology Enthusiast