Revisiting Closures
What Led Me to Reorganize This
Recently, I had an experiential intern interview at NAVER Webtoon.
It was my first interview, and maybe because I was nervous... I stumbled through my answers to CS-related questions.
One of them was a question about closures.
After coming home and thinking about it, I realized I had answered with misconceptions about closures.
To never make the same mistake again, I want to reorganize my understanding of closures.
The Etymology of Closure
In English, the word Closure is used in many different ways.
Looking it up in a dictionary, you'll find meanings like:
- Noun (permanent) closure (of a factory, school, hospital, etc.)
- Noun (temporary) closure (of a road, bridge)
- Noun The end[conclusion] (of a difficult matter)
As the noun form of Close, it's used to mean closure, termination, end, closing, etc.
However, defining it only by dictionary meaning can easily cause confusion.
This is because the etymology of closure in JS is not based on the above, but originates from Closure meaning closed in mathematics and computer science.
Closure is commonly used in expressions like closed under ~.
For example, expressions like the set of integers is closed under addition or the set of integers has closure under addition are used.


In the case of Integer operations, even after performing arithmetic operations (+, -, *, /), the result still belongs to the set of integers.
When the result of an action returns to its own set, this is called Closure.
How is Closure Expressed in JS?

In JS, closures can be expressed as shown above.
The inner function inside the outer function references variable a within the outer function's scope from outside the outer function.
Various Expressions of Closures
Closure is not a concept unique to JavaScript.
It's a universal characteristic that appears in functional programming languages.

This is captured from the official Rust guide.
As you can see, Rust also handles closures.
Since it's not a concept unique to JavaScript, the ECMAScript specification doesn't cover the definition of closures either.
Not necessarily because of this, but various literature defines closures in their own ways.
- A function that can access the context of the function that contains it
- Douglas Crockford, <<JavaScript: The Good Parts>>, O'Reilly(p68) - Intentionally defining a function in a scope so it can access that scope
- Ethan Brown, <<Learning JavaScript>>, O'Reilly(p196) - A function that can be called even after the scope created when declaring the function has disappeared
- John Resig, <<Secrets of the JavaScript Ninja>>, Manning(p116) - A function that references variables of an outer function whose lifecycle has already ended
- Song Hyeong-ju, Ko Hyeon-jun, <<Inside JavaScript>>, Hanbit Media(p157) - The combination of a function with free variables and an environment that knows the free variables
- Eric Freeman, <<Head First JavaScript Programming>>, O'Reilly(p534) - A function within a function that references local variables
- Yamada Yoshihiro, <<JavaScript Master Book>>, Gijutsu-Hyohron(p180) - A function that remembers and maintains only the variables it will use when executed, among the variables it could know from the scope when it was created
- Yoo In-dong, <<Functional JavaScript Programming>>, Insight(p31)
Examining Through MDN's Definition
"A closure is the combination of a function and the lexical environment within which that function was declared."
"A closure is a phenomenon resulting from the interaction between a function and the lexical environment at the time that function was declared"
MDN defines closures as above.
Here, lexical environment refers to outerEnvironmentReference, one of the components of the execution context.
The scope, which is the valid range of variables, is determined by the environmentRecord and outerEnvironmentReference of LexicalEnvironment, enabling scope chaining.
Consider the point when the execution context of inner function B, declared in some context A, becomes active.
With code like above, function A cannot access variable b, but function B can access variable a.
This is because function B's outerEnvironmentReference references function A.
This is exactly what combination means.
However, the inner function B doesn't always reference function A's LexicalEnvironment.
If the inner function doesn't reference external variables, it can't be called a combination.
The combination, meaning the interaction with the lexicalEnvironment at the time of declaration, is only meaningful when the inner function references external variables.

Let's look at the diagram above again.
Based on what we've understood so far, Closure can be seen as "a phenomenon that only occurs in inner functions that reference variables declared in some function".
Examining Through Code
Let's look more closely through code.
Call Stack Flow in Normal Situations
The result of console.log(++a); on line 4, which is 2, is finally output.
When the execution context of the outer function ends, references to the identifiers (a, inner) stored in LexicalEnvironment are deleted.
Consequently, the values stored at each address have no variables referencing them, making them targets for garbage collection.

This is a diagram of the call stack and execution context with VariableEnvironment and ThisBinding omitted.
This is normal behavior inside a function, with no special phenomena.
Call Stack Flow in Situations Where Closures Occur
On line 6, the result of executing the inner function is being returned.
As a result, at the point when the outer function's execution context ends, there's nothing referencing variable a.
Like the previous example, the values of a, inner variables will eventually be destroyed by the garbage collector.
Up to this point, the inner function's execution context ends before the outer function's execution context ends.
Therefore, the inner function cannot be called separately.
The environmentRecord of the inner function's execution context has no information to collect.
The LexicalEnvironment at the location where the inner function was declared is reference-copied to outerEnvironmentReference.
Since the inner function was declared inside the outer function, the outer function's LexicalEnvironment is contained.
Following Scope Chaining, it accesses variable a declared in the outer function, increases it by 1, returns the value 2, and the inner function's context ends.
Line 10 similarly returns 3.
The Principle of the Garbage Collector
The garbage collector does not include a value in the collection target if there is even one variable referencing that value.
When the inner function's execution context becomes active, outerEnvironmentReference needs the outer function's LexicalEnvironment, so it's excluded from the collection target.
Thanks to this, the inner function can access variable a.
Understanding Call Stack Flow Through Diagrams

Summary
Earlier, I said that closure is a phenomenon that only occurs in inner functions that reference variables declared in some function.
Don't forget it's a phenomenon. A closure is not a function.
Recalling what we last looked at, here variable a belonging to the outer function's LexicalEnvironment was excluded from the target.
The only case where LexicalEnvironment is excluded from the garbage collector's collection target after the function's execution context ends is when an inner function that references local variables is passed to the outside.
"A phenomenon that only occurs in inner functions that reference variables declared in some function" means "a phenomenon where the outer function's LexicalEnvironment is not garbage collected".
Based on this, if we revise the definition, it becomes:
A closure is a phenomenon where, when inner function B that references variable a declared in some function A is passed to the outside, variable a does not disappear even after A's execution context has ended

Let's look at the diagram again with this concept in mind.
Do you understand it now?
Precautions
Does passing to the outside only mean
return?
Let's look at it through code.
Local variables are referenced inside the handler function to be registered with the method (addEventListener) of a separate external object, DOM.
Both situations are closures because inner functions that reference local variables were passed to the outside.