Let's start simple
Imagine having a fridge with a cake, some milk, and a few eggs inside.

Every time we open it, we want to grab something to eat, and we’ll keep doing that until it’s empty. So we decide to “open” the fridge by calling the function fridge(), but surprise: instead of showing us what we grabbed, the program returns the declaration of the function grabSomething():

But wait: grabSomething() is exactly the function we expected to run automatically once we called fridge(), and yet… nothing happened.
It’s as if, instead of actually opening the fridge, we found a sticky note that says “open the fridge and grab something.”
Useful? Not really.
However, if we look at the implementation of fridge() calmly, the result makes perfect sense. After all, fridge() returns the declaration of a function: it doesn’t execute it. Philosophically speaking, the act of “grabbing something from the fridge” is implicit in real life, but in our case, that’s not enough: we really want those eggs.
A clever eye might say, looking at the code:
“Well, easy: just call it directly like this → fridge()().”
And they’d be right: this way, the console would print 'egg'.
The problem is that it stops there.
Why calling fridge()() is not a good idea
That call works because fridge() returns a function and we execute it immediately, but the inner function and its state disappear right away: the closure managing the “fridge” does not survive beyond that single execution.
And this is where the term closure comes in: it’s called that because the function “closes over” the variables in the context where it was created, keeping them accessible even after that scope has ended.
In other words, fridge()() creates the closure and consumes it right away. After the inner function grabSomething() finishes printing 'egg', the engine no longer has any reference to it.
The Lexical Environment that contained the storage is then released from memory (garbage-collected). That’s why every time you call fridge()() it’s like calling it for the first time: the function doesn’t “remember” anything about its previous state, because that state no longer exists.

What can be a good alternative?
To fix this behavior, simply store the returned function reference in a variable:

This way, we’re no longer creating and destroying the closure on every call, but rather keeping it alive in memory, together with its Lexical Environment (we talked about it in detail here).
The variable openTheFridge becomes our “pass” to access the same storage instance every time we call the function.
While fridge()() creates a new instance at every invocation (and thus “forgets” what was in the fridge), openTheFridge() preserves the internal state between calls because it maintains the link to the original closure.

Different variables, different instances!
Now, our fridge is empty and we’re still starving.
Too lazy to go shopping, we remember our parents always have a full fridge! Let’s hope it’s the same this time:

Without shame, we start mooching:

But how is it possible that even though we’re calling the same fridge(), with the same internal storage, this one doesn’t return 'Fridge is empty' like it did for openTheFridge()?
Each call to fridge() creates a new closure with its own lexical environment (that is, a new “fridge” in memory).
openTheFridge and openTheFridgeAtParentsHouse are two different functions, each with its own separate storage.
When you empty the first one, the second stays full: two fridges, two worlds, zero interference.
But wait: doesn’t that mean closures clog up memory? What happens under the hood? Where have we seen them before?
And most importantly, why do they remind us so much of classes?
I’ll answer all of that in the next article!