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();,Ais executed, creating acountvariable and an internal function B. SinceAreturnsB, theCvariable actually has a reference toB. The functionBcan then access the count variable inA. - Function
Bcan access the count variable inAbecauseBis a closure. This is becauseBis 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,Bincrements the value ofcountand displays that value on the console. -
A's execution context ends whenBis created, butA's local variables are not reclaimed as long asBreferences its local variables (such ascount). - Only when
Bis no longer referenced will the count variable and other local variables inAbe recovered. In this example, sinceCstill 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
countand keeps it accessible to the internal functionB. Even if the execution context ofAterminates, the state of count remains in memory becauseBcontinues to refer to this state. - On each call to
B: Each call toC()is actually a call toB(), which uses thecountstored 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