First, let’s sort out a few confusing concepts
-
“Execution environment”, abbreviated as “environment”, or sometimes translated as “context”. There are two types: global (execution) environments and local (execution) environments (functions). After all the code in the environment has been executed, the environment is destroyed, along with all variables and functions in the environment (the global environment is not destroyed until the program exits, such as closing the web page and browser).
-
Each function has its own execution environment, the local environment. When the execution stream enters a function (local environment), the environment of the function is pushed into an environment stack. After the function is executed, the stack ejects its environment, returning control to the previous execution environment.
-
Variable object: Each environment has a variable object associated with it. All variables and functions defined in the environment are stored in this object.
-
Active object: The variable object of the function (local environment) is the active object. The active object contains: arguments to a function + variables defined in a function and function declarations. Initially, it contains only two variables: the Arguments object and this.
-
The variable object of the global environment always exists, while the variable object of the local environment (that is, the active object) only exists during the execution of the function.
-
Scope chain: A scope chain is essentially a list of Pointers to variable objects in each execution environment.
When code is executed in an environment, a scope chain of variable objects is created. The front end of the scope chain is always the variable object of the environment in which the code is currently executing; Under a variable object from contains (external) environment, namely “parent execution environment”, then the next under the variable object from another contains (external) environment, namely the execution environment 】 【 ye, that extends to the overall execution environment (global execution environment variable objects are always the last one in the scope chain object).
-
The scope chain does:
Ensures orderly access to all variables and functions that the execution environment has valid access to.
- The above sentence has two key words that illustrate the two specific functions of the scope chain. They are:
effective
: Does the current environment have permission to access this identifier (the identifier refers to the name of a variable or function)The orderly
Identifier resolution (variable lookup, or access to variables) is really a process of searching identifiers level by level along the scope chain. The search process always starts at the front of the scope chain, and then steps back until the identifier is found. (An error is usually reported if the identifier is not found)- In addition to the above two functions, there is another hidden function: collect and maintain all declared identifiers
- The above sentence has two key words that illustrate the two specific functions of the scope chain. They are:
-
[Scope] : The formation of scope is based on the scope chain. A scope is actually a “scope” in which the identifier (variable name/function name) is valid and accessible. Therefore, what we usually see as “scope of variable XXX” really means “effective (accessible) scope of variable XXX in code”.
-
In Javascript, there are two types of scope for variables: global scope and local scope (not to be confused with “global execution environment” and “local execution loop”, which are two different concepts). Let’s take an example: Given that A variable A is defined with var in the global execution environment, the variable object in the global execution environment contains variable A. Since the variable object in the global execution environment is at the end of any scope chain, this means that variable A can be referenced no matter where in the code. Therefore, The scope (scope of use) of variable A is global. Here are several examples: Assumption in a function (local execution environment) using var defines a variable B, then local execution environment active object contains the variable B, due to local execution environment live objects in the scope chain is located in the front, that is to say, in the global execution environment, we can’t quote this function of variable B, therefore, The scope (scope of use) of variable B is local.
-
As a bonus, variables declared using VAR are automatically added to the nearest environment. Within a function, the closest environment is the local environment of the function. If a variable is not declared with var when it is initialized, it is automatically added to the global environment.
-
By the way, there is no block-level scope in Javascript (another story after ES6).
Two, to give a specific chestnut
function compare(value1, value2) { if (value1 < value2) { return -1; } else if (value1 > value2) { return 1; } else { return 0; } } var resulet = compare(5, 10);
In the code above, the global execution environment variable object contains compare and result. When compare() is called, a local environment is generated for it, and an active object is created with arguments objects, value1, value2 (and actually this). Compare’s active object is first in the scope chain of the compare() local execution environment, and the global variable object is second. See the following figure for details:
Compare () = compare(); compare() = compare()
- First, global variables always exist, whereas local variables (live objects), such as compare(), only exist during the execution of the function.
- When you create compare(), you create a scope chain that precontains the global variable object. This scope chain is stored in the [[scope]] property inside the function.
- When compare() is called, it creates an execution environment for the function, and then copies the scope chain in the function’s [[scope]] property as the scope chain for the local environment (which at this point only contains global variable objects). Next, create the local environment’s variable object (that is, the active object) and add the active object to the front of the local environment’s scope chain. At this point, the scope chain for the local environment is fully created. So, for the context in which compare() is executed, the scope contains two variable objects: a local active object and a global variable object.
Let’s talk about closures
Closures are functions that have access to variables in the scope of another function.
That is, a closure is a function that has access to variables in the scope of another function.
A common way to create closures is to create another function inside one function.
Why do WE talk about closures? Because closures have an intimate relationship with scope chains. (run
A closure can access the variables of a higher-level function because of the scope chain.
In general, when the function completes, the live objects of the local environment are destroyed, and only the global execution environment (the variable objects of the global execution environment) are kept in memory. Closures, however, are different.
A function defined inside another function adds its active object containing the function (the outer function) to its scope chain.
Function A defines A function B. Function B adds the active object of its external function (function A) to its scope chain. In addition, the active object of function A is not destroyed when function A is finished, because function B’s scope chain still refers to the active object of function A. The active object of function A is destroyed when function B’s scope chain is destroyed.
Let me give you a more specific example.
function createComparisonFunction(propertyName) { return function(object1, object2) { var value1 = object1[propertyName]; var value2 = object2[propertyName]; if (value1 < value2) { return -1; } else if (value1 > value2) { return 1; } else { return 0; }}; } // create a function var comparenNames = createComparisonFunction("name"); // call function var resule = compareNames({name:"Nicholas"}, {name:"Greg"}); // Unreference anonymous functions compareNmaes = null;
In the code above:
- The variable objects in the global execution environment are: comparenNames and Resule
- The active objects in the execution environment of the createComparisonFunction() function are: Arguments object and propertyName
- The active objects in the execution environment of anonymous functions are: Arguments object, object1, object2, Value1, value2
The scope chain generated during the call to comparenNames() is shown below:
As we said earlier:
Identifier resolution (variable lookup, or access to variables) is really a process of searching identifiers level by level along the scope chain. The search process always starts at the front of the scope chain, and then steps back until the identifier is found.
According to the scope chain in the figure above, so:
- Anonymous functions can access their own local variables, variables in createComparisonFunction(), and variables in the global environment;
- CreateComparisonFunction () can only access its own local variables and variables in the global environment, not variables in anonymous functions;
- In the global environment, only variables in the global environment can be accessed, not variables in createComparisonFunction() and variables in anonymous functions.