Although closures are a fundamental idea in JavaScript, newcomers may find them vague and challenging to grasp. Specifically, the ECMA standard's definition can be challenging to comprehend without any real-world experience. As a result, rather than going into great length to explain the notion of closures in this post, we will make it easy for you to comprehend by using actual code.
1. Closure
function A(name){
function B(){
console.log(name);
}
return B;
}
var C = A("Closure");
C();//Closure
This is the simplest closure.
Now that we know the fundamentals, let us briefly examine how this differs from a typical function. The following is how the aforementioned code appears when translated into natural language:
- Define a normal function A, with argument name
- Define a regular function B in A, and in B, refer to the external variable name
- Return B in A
- Execute A and assign the result to variable C
- Run C
One statement can encapsulate these five operations:
Function B inside function A and variable name are referenced by variable C outside function A.
With a little modification, this statement defines a closure as follows:
A closure is created every time a function is created—at the time when the function is created. Every function has an associated closure. Nesting functions are not required.
Therefore, performing the above five operations defines a closure.
Uses of Closures
Before we understand the uses of closures, let's understand JavaScript's GC (Garbage Collection) mechanism.
In JavaScript, when an object is no longer referenced, it will be reclaimed by the GC, otherwise, it will continue to be kept in memory.
In the above example, B depends on A because B is defined within A, and A is indirectly referenced by C because the external variable C references B.
That is, A will not be collected by the GC and will continue to be kept in memory. To prove this reasoning, let's slightly improve the above example.
function A(){
var count = 0;
function B(){
count ++;
console.log(count);
}
return B;
}
var C = A();
C();// 1
C();// 2
C();// 3
- If we call
var C = A();
,A
is executed, creating acount
variable and an internal function B. SinceA
returnsB
, theC
variable actually has a reference toB
. The functionB
can then access the count variable inA
. - Function
B
can access the count variable inA
becauseB
is a closure. This is becauseB
is a closure, and closures preserve the context in which they are created (e.g., local variables). - When
C()
is called, it actually calls functionB
. Each timeC()
is called,B
increments the value ofcount
and displays that value on the console. -
A
's execution context ends whenB
is created, butA
's local variables are not reclaimed as long asB
references its local variables (such ascount
). - Only when
B
is no longer referenced will the count variable and other local variables inA
be recovered. In this example, sinceC
still refers toB
, the value of count is not recovered, nor is the execution context ofA
.
Why is count not reset?
Closure mechanism:
- The closure keeps the state of
count
and keeps it accessible to the internal functionB
. Even if the execution context ofA
terminates, the state of count remains in memory becauseB
continues to refer to this state. - On each call to
B
: Each call toC()
is actually a call toB()
, which uses thecount
stored in the closure and does not reinitialize it.
Thus, if you define some variables in a module and want to keep these variables in memory but not “pollute” the global variables, you can define this module using closures.
Top comments (1)
Unfortunately, this isn't correct. A closure is created every time a function is created - at the time when the function is created. Every function has an associated closure. Nesting functions is not required.
Misconceptions About Closures
Jon Randy 🎖️ ・ Sep 27 '23