I have written an article before about What exactly is a JavaScript closure? about understanding closures. I think it is very clear and I can easily understand the reasons for closures. However, I read the comments and they all say that I understand the scope. Only chains and active objects can truly understand closures. I didn't think so at first. Later, when I communicated with colleagues in the company, I found that scope and execution environment are indeed very important and very basic. They are very helpful for understanding JavaScript closures, so I wrote an article about them. Understanding of scope and execution environment.
Scope
Scope is the accessible scope of variables and functions, which controls the visibility and life cycle of variables and functions. In JavaScript, the scope of variables has global scope and local scope.
Pure JavaScript scope is still easy to understand. In some C-like programming languages, each piece of code within curly braces has its own scope, and variables are invisible outside the code segment where they are declared. This is the block-level scope, and this is where JavaScript easily misunderstands beginners. JavaScript does not have block-level scope, only function-level scope: variables are visible within the function body and sub-functions in which they are declared. .
A variable that is not declared within a function or declared without var is a global variable. It has a global scope. All properties of the window object have a global scope; it can be accessed anywhere in the code. It is declared inside the function and decorated with var. The variables are local variables and can only be used within the function body. Although the parameters of the function do not use var, they are still local variables.
However
If it were just like this, then the JavaScript scope problem would be very simple. However, the problems caused by function sub-functions make the scope more than simple. The big guy comes on stage - the execution environment or runtime context (good fellow): The execution context defines other data that variables or functions have access to, and determines their respective behaviors. Each execution environment has a variable object (VO) associated with it. All variables and functions defined in the execution environment will be stored in this object. The parser will access this internal object when processing data.
The global execution environment is the outermost execution environment. In the web browser, the global execution environment is the window object, so all global variables and functions are created as attributes and amplifications of the window object. Each function has its own execution environment. When the execution flow enters a function, the function environment will be pushed into a function stack. After the function is executed, the execution environment will be popped out of the stack and destroyed, and all the information stored in it will be pushed. The variable and function definitions are then destroyed, and control is returned to the previous execution environment. The global execution environment will not be destroyed until the application exits (the browser is closed).
Scope chain
When code is executed in an environment, a scope chain (sc) of variable objects will be created to ensure orderly access to variables and functions that the execution environment has access to. The first object in the scope is always the variable object (VO) of the environment where the code is currently executed
If the execution environment is a function, then its activation object (AO) is used as the first object in the scope chain, the second object is the containing environment, and the next one is the containing environment of the containing environment. . . . .
During the running of the function, the resolution of identifiers is a process of searching level by level along the scope chain. Starting from the first object, going back step by step until an identifier with the same name is found. Once found, no more Continue to traverse and report an error if it cannot be found.
Let’s look at closures again
A previous blog once concluded: As long as there is the possibility of calling internal functions, JavaScript needs to retain the referenced functions. Moreover, the JavaScript runtime needs to track all variables that reference this internal function until the last variable is discarded before the JavaScript garbage collector can release the corresponding memory space. Looking back, it is easier to understand. The variables defined by the parent function are in the scope chain of the child function. If the child function is not destroyed, all variables and functions in its scope chain will be maintained and will not be destroyed.
Due to the internal function (the click event handler may be called at any time), its scope chain cannot be destroyed (not to mention that in this example, i is in the global scope and can only be destroyed when the page is unloaded). The value of i The length value after the for loop is executed is always maintained, so length will be alerted every time onclick is triggered.
Why does this work? At this time, the variable referenced by onclick becomes n, and due to the immediate execution of the function, each onclick function maintains the corresponding n (0~length-1) in the scope chain. , that’s it at this time.
Finally
In fact, after understanding the execution environment and scope chain, closure becomes obvious, but closure cannot be abused. As can be seen from the above example, closure will make the sub-function maintain its scope chain. All variables, functions and memory consume a lot of memory. Try to destroy variables that are no longer used by the parent function when using them.