The result is straightforward as the above, it will print that
text variable. Let’s push it a little bit.
Now we use the Immediately-Invoked Function Expression (IIFE), since the
outside() will return a function, we just simply add another
() after it, to invoke that function. The result is the same, and it is easy to understand. Nothing strange here.
Let’s go even further.
Wow, something interesting happened, let’s break them into pieces:
- First, we define a function called
outside(), it will return a anonymous function.
- Second we assign the
trueOutside, now the variable
trueOutsidewill hold that inner anonymous function.
- Finally we execute that
trueOutside()which will invoke that inner function.
It should throws an error - “
text is not defined“. Since the variable
text is not there when it executed. But it still behaves as normal. What happened? This is what we called closure comes into play. The
trueOutside here has become a closure.
It hard to understand, especially when you come from a traditional programming language like C, C#, Java, you will be very confused at this stage, the reason is that you try to use the common memory model in the above languages such as stack to adopt to this scenario. What’s in your mind is, when the
trueOutside() runs, the
outside() is not on the stack, since it has been executed so should be removed from the stack. Thus, when
trueOutside() tries to execute, that variable
text shouldn’t be there, so the result should be a “
text is not defined“.
This is the reason why I told you not to follow that accepted answer on stack overflow, since it is tried so hard to adopt the stack theory like “as if a ‘stack frame’ were allocated on the heap”… Totally absurd even for an analogy.
The concept closure can’t be explain well with “stack” but “execution context” or “execution environment”.
We’ll talk more about the execution environment later. Let’s check another common mistake. You can see many definitions online as the following one from the famous W3School:
A closure is a function having access to the parent scope, even after the parent function has closed.
To be honest, this is deadly wrong. Because it is nothing to do with the parent function and nothing to do with accessing behaviour either, Let’s prove it with the following code.
trueOutside() for 3 times, Let’s put down your questions first since we will explain later, let’s follow the above definition, it said the inner function can access to the parent scope even when it is closed, OK, now we executed the parent function
There is another post from a famous writer who tries to use scoping chain to explain this, but it doesn’t make sense as the reason above. Since even the interpreter tries to find the variable
text follow the scoping chain, it won’t succeed since that
outside() function is not valid anymore.
The magic happens when you assign the returned function to that variable
trueOutside, I said before, the
trueOutside has become a closure. According to MDN, the closure has the following properties.
A closure is a special kind of object that combines two things:
- a function
- the environment in which that function was created.
- The environment consists of any local variables that were in-scope at the time that the closure was created.
So, it is easy to understand now, the closure
trueOutside, it not only contains that returned anonymous function, but also it contains the variable
text, since it was exist when the closure was created. So, it can executed well. And it can be explained the last example I showed you before. Let’s review it.
Why it can accumulate? It is just that simple since the variable
trueOutsidehas created a new execution context for that inner function, and it stores all the status inside itself without affecting the original parent function
This is pretty much of closure. Maybe there is another famous example you have seen, which is the following, a closure when looping. Resulting in a very strange result.
What you expect the output to be? Since the variable
i has increased step by step during the loop and the value had stored step by step into that function. It should output the following,
But instead, it will output like this: