In the article JS Prototype and Inheritance that front-end development must know, I mentioned that I will write an article on closures. In addition, I have recently found that I need to strengthen my closure application capabilities, so this article cannot be postponed any longer. This article talks about function closures and does not involve object closures (such as using with). If you think what I said is wrong, please feel free to comment and give me advice.
1. The theory of closure
First of all, you must understand the following concepts:
Execution environment
Every time a function is called (when the function is executed), the system will Create a closed local running environment for the function, which is the execution environment of the function. Functions are always executed in their own execution environment, such as reading and writing local variables, function parameters, and running internal logic. The process of creating an execution environment includes creating the scope of the function, and the function is also executed in its own scope. From another perspective, each function execution environment has a scope chain, and the scope chain of the child function includes the scope chain of its parent function. Please see below for scope and scope chain.
Scope, scope chain, calling object
Function scope is divided into lexical scope and dynamic scope.
Lexical scope is the scope when the function is defined, that is, static scope. When a function is defined, its lexical scope is determined. The lexical scope describes the scope of the function under the nested relationship of the function structure. At this time, the scope chain of the function is formed. The scope chain is to connect these scopes with nested hierarchical relationships. The function's internal [[scope]] attribute points to this scope chain.
Dynamic scope is the scope when a function call is executed. When a function is called, the [[scope]] attribute inside the function is first pointed to the scope chain of the function, and then a calling object is created, and the calling object is used to record the function parameters and local variables of the function, and put them in the scope chain. Top of domain chain. Dynamic scope is created by adding the calling object to the top of the scope chain. At this time, [[scope]] not only has the scope chain when it is defined, but also has the calling object created when it is called. In other words, the scope in the execution environment is equal to the scope chain determined when the function was defined plus the calling object just created by the function, thus forming a new scope chain. So it is a dynamic scope, and the scope chain also changes accordingly. Looking at the scope here, it is actually an object chain. These objects are the calling objects created when the function is called, and the calling objects above it until the top-level global object.
For example, if function A in the global environment has a function B nested within it, then the scope chain of function B is: the scope of function B -> the scope of function A -> the scope of the global window. When function B is called, when looking for an identifier, it will be searched according to the scope of function B -> the scope of function A -> the scope of the global window. In fact, it will be searched according to the calling object of function B -> function The calling object of A -> global object is searched in this order. That is to say, when a function is called, the scope chain of the function is actually the calling object chain.
Closure
In a dynamic execution environment, data changes in real time. In order to maintain the values of these non-persistent variables, we use closures as a carrier to store these dynamic data (read the following You will understand this sentence very well if you apply it). Definition of closure: The so-called "closure" refers to an expression (usually a function) that has many variables and an environment bound to these variables, so these variables are also part of the expression.
A closure is an internal function nested inside a function, and the internal function can access all local variables, parameters and other internal functions declared in the external function. When the inner function is called outside the outer function, a closure is generated. (In fact, any function is an internal function of the global scope and can access global variables, so it is a closure of window)
For example, the following example: