Closure in JavaScript Explained - Esoteric JS Part 3
September 25, 2021Disclaimer: This post has got highly inspired by the JS Hard Parts Video series from Will Sentence.
Hi, today I want to write about a very esoteric concept in JavaScript – Closure. This concept lays a foundation for stuff like Iterators or Currying.
By the end of this blog post you should understand why the code snippet below is working.
Without further ado, let’s get started.
// Why is this working?!
function returnOtherFunction(array) { // Step 1
let arrayIndex = 0;
function inner() {
const element = array[arrayIndex];
arrayIndex++;
}
return inner;
}
const returnNextArrayElement = returnOtherFunction([8,9,10]) // Step 2
const firstelement = returnNextArrayElement() // Step 3
const secondelement = returnNextArrayElement() // Step 4
Let’s analyze how JavaScript is executing this function.
Step 1
function returnOtherFunction(array) {...} // Step 1: We are saving the function definition of returnOtherFunction to the Global Memory (Figure 1)
Step 2
const returnNextArrayElement = returnOtherFunction([8,9,10])
// We are defining a const with the identifier ,,returnNextArrayElement'' and the value of - we don't know yet -, because we have
// to call the function returnOtherFunction([8,9,10]) with the argument [8,9,10] -> We are opening a new local execution context.
In the local execution context we are filling in the local memory, as shown in the diagram. Keep in mind, inner() is not being called! Only its function definition is being returned. There are no parentheses which would indicate a calling.
So far so good, let’s have a look at the next line.
Step 3
const firstelement = returnNextArrayElement()
Now it’s getting interesting! Remember, returnNextArrayElement() holds the function definition of inner()! So, inner() is being called! But…
The function definition of inner() is:
function inner() {
const element = array[arrayIndex];
arrayIndex++;
}
Where do we get the param of array and arrayIndex? These variables are neither defined in the local scope nor the global scope. Why is there no error?
And this is the part where the so-called concept of Closure is coming in 👋 Say hi!
Closure
When you are returning a function(definition) within another function (this is called “High Order Functions”, if you aren’t familiar with that, go and check out my blog post about HOC )
You are also returning the properties defined in the local scope of the Higher Order Function (the “outer” function). But you are only returning it as a hidden property named scope which you can’t access directly, unless you are doing it in the callback function. So it’s kind of stuff in a backpack: It is attached to the function, but it’s not visible.
Developers often refer to this “backpack” as Closure. But the problem is, that Closure is also the overall concept and this often confuses a lot of people. Another, more precise name for this “backpack” would be C.O.V.E. or persistent data in the variable environment.
Going back again to the function:
const firstelement = returnNextArrayElement()
function inner() {
const element = array[arrayIndex]; // arrayIndex = 0, and the element at the index of 0 is 8
arrayIndex++; // We are updating the arrayIndex to 1;
}
Now we are calling the same function again and element is assigned to 9, and the hidden arrayIndex is being updated to 1. Simple, isn’t it?
const secondelement = returnNextArrayElement()
I hope, I could help you to understand the concept of closure. See you next time 🐝