In-depth understanding of javascript closures series 2 - Closures from the perspective of execution environment

previous words

This article analyzes the closure from the perspective of the execution environment, and explains the code content line by line in a graphical way.

Description: The following describes the diagrams in detail in the order of the code execution flow.

function foo(){
    var a = 2;

    function bar(){
        console.log(a);
    }
    return bar;
}
var baz = foo();
baz();

[1]: The code execution flow enters the global execution environment, and the code in the global execution environment is declared and promoted.
write picture description here

[2]: The execution flow executes the 9th line of code var baz = foo(), and calls the foo() function. At this time, the execution flow enters the execution environment of the foo() function, and the code in the execution environment is declared and promoted. At this time, there are two execution environments in the execution environment stack, and the foo() function is the execution environment where the current execution flow is located.
write picture description here

[3]: The execution flow executes the code in the second line var a = 2; perform LHS query on a, and assign a value of 2 to a.
write picture description here

[4]: The execution flow executes the 7th line of code return bar; the bar() function is returned as the return value. It stands to reason that the foo() function has been executed at this time, and its execution environment should be destroyed, waiting for garbage collection. But because its return value is the bar function, there is a free variable a in the bar function, and the value of the variable a needs to be found in the execution environment of the foo() function through the scope chain, so although the execution environment of the foo function is destroyed, its The variable object cannot be destroyed, but changes from an active state to an inactive state; while the variable object in the global execution environment becomes active; the execution flow continues to execute the code on line 9 var baz = foo(); put foo( ) function return value bar function is assigned to baz.
write picture description here

[5]: The execution flow executes the 10th line of code baz(); by looking up the value of baz in the global execution environment, baz holds the return value bar of the foo function. Therefore, when baz() is executed at this time, the bar() function will be called. At this time, the execution flow enters the execution environment of the bar() function, and the code in the execution environment is declared and promoted. At this time, there are three execution environments in the execution environment stack, and the bar() function is the execution environment where the current execution flow is located.

In the process of declaration promotion, since a is a free variable, it needs to be searched through the scope chain bar() –> foo() –> global scope of the bar() function, and finally the code in the foo() function The second line of finds var a = 2; and then finds that the value of a is 2 in the execution environment of the foo() function, so assign 2 to a.
write picture description here

[6]: The execution flow executes the 5th line of code console.log(a);, calls the internal object console, and logs the method from the console object, passing a as a parameter. The value of a found in the execution environment of the bar() function is 2, so 2 is finally displayed on the console.

[7]: The execution flow executes the 6th line of code, and the execution environment of bar is popped off the execution environment stack and destroyed, waiting for garbage collection, and the control is returned to the global execution environment.

write picture description here

In fact, the execution environment of the foo() function here is destroyed, but its variable object is always in the memory space due to the existence of the closure. This can be seen at a glance from the pop-out of the execution environment stack. (The execution environment of the function is created when it is called and destroyed when it returns), and its active object remains in memory~)

[8]: When the page is closed, the execution environment used is destroyed.

Summarize:

As can be seen from the fifth step of the above description, due to the closure of the bar() function, although the execution environment of the foo() function is destroyed, its variable object always exists in the memory space. The purpose is to make it possible to access the parent function foo() through the scope chain when calling the bar() function, and get the variable value stored in its variable object. Until the page is closed, the variable object of the foo() function will be destroyed together with the global variable object, thereby freeing the memory space

Because closures take up memory space, use closures with caution. Try to dereference in time after using the closure, so that the memory can be released earlier.

//通过将baz置为null,解除引用
function foo(){
    var a = 2;
    function bar(){
        console.log(a);//2
    }
    return bar;
}
var baz = foo();
baz();        
baz = null;
/*后续代码*/

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325640354&siteId=291194637