- var ClassA = function () {
- THIS.PROP1 = 1;
- }
- CLASSA.PROTOTYPE.FUNC1 = function () {
- var that = this,
- VAR1 = 2;
- function A () {
- return function () {
- alert (VAR1);
- alert (THIS.PROP1);
- }.apply (that);
- };
- A ();
- }
- var obja = new ClassA ();
- Obja.func1 ();
You should write the above code like this, in fact, I want to express here is sometimes a method to define the place and the use of the place will be 108,000 miles apart, that method executes, it can access which variables, can not access which variables, how to judge this? This is the problem we need to analyze this time-lexical scopes
Lexical scopes: The scope of a variable is determined when it is defined, not when it is executed, that is, the lexical scope depends on the source code, which can be determined by static analysis, so the lexical scope is also called a static scope. With and Eval excepted, so can only say JS scope mechanism is very close to the lexical scope (lexical scope).
Below, through a few small cases, began to understand the lexical scope and closure of the necessary, JS implementation of some of the underlying concepts and theoretical knowledge.
Recurrence of the classic case list
1, the classic case of a
- /* A piece of code under the Global (window) field * *
- function A (i) {
- var i;
- alert (i);
- };
- A (10);
Question: What does the above code output?
Answer: Yes, just pop 10. The implementation process should be the case
- The A function has a formal parameter I, when the A function is invoked, the argument 10 is passed, and the formal parameter i=10
- Next, define a local variable I with the same name, and not assign a value
- Alert Output 10
- Think: is the local variable i and formal parameter i the same storage space?
2, the classic case two
- /* A piece of code under the Global (window) field * *
- function A (i) {
- alert (i);
- Alert (arguments[0]); Arguments[0] should be the formal parameter I
- var i = 2;
- alert (i);
- Alert (arguments[0]);
- };
- A (10);
Question: What does the above code output? ((10,10,2,10 10,10,2,2))
Answer: The result of the operation in Firebug is the second 10,10,2,2, guess right ..., the following is a brief detail of the implementation process
- The A function has a formal parameter I, when the A function is invoked, the argument 10 is passed, and the formal parameter i=10
- The first alert puts the value of parameter I at 10 output
- The second alert puts the arguments[0] output, which should also be I
- Then define a local variable I and assign a value of 2, at which point the local variable i=2
- The third alert outputs the value of the local variable I by 2
- The fourth alert again arguments[0] Output
- Think: Can we show that the values of local variable i and parameter I are the same?
3, the classic case three
- /* A piece of code under the Global (window) field * *
- function A (i) {
- var i = i;
- alert (i);
- };
- A (10);
Question: What does the above code output? ((undefined 10))
Answer: The result of the operation in the Firebug is 10, the following is a brief explanation of the specific execution process
- The first sentence declares a local variable i with the same name as the formal parameter I, and according to the result we know that the latter I is pointing to the
- Formal parameter I, so here is equal to the value 10 of the parameter I to assign the local variable i
- The second alert, of course, outputs 10.
- Thinking: Combined with column two, here is a basic description of the local variable i and parameter I point to the same storage address!
4, the classic case four
- /* A piece of code under the Global (window) field * *
- var i=10;
- function A () {
- alert (i);
- var i = 2;
- alert (i);
- };
- A ();
Question: What does the above code output? Boy, look at this, it's not going to kill you! Wow haha, don't give you the option)
Answer: The result of the operation in the Firebug is undefined, 2, the following is a brief explanation of the actual execution process
- First Alert output undefined
- Second Alert Output 2
- Thinking: What the hell happened?
5, the classic case of five ...... N
See a few examples above, you may think, how can I write JS for several years, how such a simple example will hesitate, the result may also be wrong. The reason may be: we can quickly write a method, but in the end how the implementation of the method inside? What about the details of the execution? You may not have had a thorough study and understanding. To understand these details, you need to understand how the JS engine works, so below we will be the JS engine to a method of the parsing process a little more in-depth introduction
Parsing process
1. Order of execution
- Compiled language, compilation steps are divided into: lexical analysis, syntax analysis, semantic check, code optimization and byte generation.
- interpreted language, through lexical analysis and syntactic analysis of the parse tree, you can begin to explain the implementation. Here is a simple primitive about the principle of parsing process, only as a reference, the detailed parsing process (various JS engine and different) still need a further study
The JavaScript execution process, if a document stream contains multiple script snippets (JS code separated by a script tag or a JS file that is introduced), they run in the following order:
- Step 1. Read the first code snippet (the JS execution engine does not execute the program in one line, but a section of the execution)
- Step 2. Do lexical analysis and grammar analysis, mistakes are reported grammatical errors (such as parentheses do not match, etc.), and jump to step 5
- Step 3. "Pre-resolution" for "VAR" variables and "function" Definitions (never error, because only correct declarations are parsed)
- Step 4. Execute code snippet, error errors (such as variable undefined)
- Step 5. If you have the next code snippet, read the next code snippet, repeat step 2
- Step 6. End
2. Special Instructions
All JS code under the Global Domain (window) field can be viewed as an "anonymous method" that is automatically executed, while other methods within this "anonymous method" are executed when the call is displayed
3. Key steps
The above process, we are mainly divided into two stages
- Parsing: is to construct a legal parsing tree by parsing and pre parsing.
- Execution: Execution of a specific FUNCTION,JS engine creates an execution environment (EXECUTIONCONTEXT) and active objects (Activeobject) (they belong to the host object, consistent with the life cycle of the function instance) when executing each instance of the function.
3. Key Concepts
Here, we will put more emphasis on the following concepts, which can be expressed in a single entity below, to facilitate understanding
- The syntax Analysis Tree (SYNTAXTREE) can visually express the relevant information of this Code, the specific implementation is the JS engine to create a number of tables, to record the set of variables in each method (variables), method set (functions) and scope (scope), etc.
- The execution Environment (ExecutionContext) is understood to be an object that records the currently executing method "external description", recording the type, name, parameters, and active object (Activeobject) of the method being executed.
- An active object (Activeobject) is understood to be an object that records the currently executing method "Internal execution information," which records the internal set of variables (variables), the inline function sets (functions), the arguments (arguments), The required information for the execution of the scope chain (Scopechain), where the internal variable set (variables), the inline function set (functions) is copied directly from the parse tree created by the first step.
- Lexical scopes: The scope of a variable is determined when it is defined, not when it is executed, that is, the lexical scope depends on the source code, which can be determined by static analysis, so the lexical scope is also called a static scope. With and Eval excepted, so can only say JS's scope mechanism is very close to the lexical scope (lexical scope)
- Scope Chain: The implementation mechanism of lexical scopes is the scope chain (Scopechain). A scope chain is a mechanism for searching by name (name lookup), first looking in the activeobject of the current execution environment, not found, then searching through the scope chain to the parent Activeobject to find the global calling object
4. Entity representation
Analytic simulation
It's pretty hazy to see here, I guess. What is the parsing tree, what is the parsing tree, what is the scope chain, how do we do it, what is the activity object, and so on, or not too clearly, we will simulate the whole parsing process through a piece of actual code, we will parse the tree, The active object is actually created to understand the scope and how the scope chain is implemented.
1. Analog Code
- /* A piece of code under the Global (window) field * *
- var i = 1,j = 2,k = 3;
- function A (o,p,x,q) {
- var x = 4;
- alert (i);
- Function B (r,s) {
- var i = 11,y = 5;
- alert (i);
- function C (t) {
- var z = 6;
- alert (i);
- };
- function expression
- var d = function () {
- alert (y);
- };
- C (60);
- D ();
- };
- B (40,50);
- }
- A (10,20,30);
2. Syntax Analysis tree
The above code is very simple, that is, the first definition of some global variables and global methods, then in the method to define local variables and local methods, now the JS interpreter read this code to start parsing, the preceding mentioned JS engine will first through the grammar analysis and pre-resolution to get the syntax analysis tree, as for the syntax analysis tree long what kind of, Have some information, below we have a simple structure: a JS object (in order to clearly represent the various objects of the reference relationship, here is only pseudo object representation, may not be able to run) to describe the syntax analysis tree (which we are familiar with, the actual structure we do not go into the study, it must be more complex, This is intended to help understand the parsing process and simplify it specifically.
- /**
- * Simulate the creation of a parse tree that stores variables and methods within a function
- */
- var syntaxtree = {
- The representation of global objects in the parsing tree
- window: {
- variables:{
- i:{Value:1},
- j:{Value:2},
- k:{Value:3}
- },
- functions:{
- A:this.a
- }
- },
- a:{
- variables:{
- x: "Undefined"
- },
- functions:{
- b:this.b
- },
- Scope:this.window
- },
- b:{
- variables:{
- Y: "Undefined"
- },
- functions:{
- C:THIS.C,
- D:this.d
- },
- Scope:this.a
- },
- c:{
- variables:{
- Z: "Undefined"
- },
- functions:{},
- scope:this.b
- },
- d:{
- variables:{},
- functions:{},
- Scope: {
- Myname:d,
- scope:this.b
- }
- }
- };
The above is a simple representation of the parse tree, as we analyzed earlier, where the parse tree mainly records the set of variables (variables) in each function, the method set (functions), and scope (scope)
Syntax Analysis tree key points
- 1 variable set (variables), only variable definition, no variable value, this time the variable value is all "undefined"
- 2 scope (scope), according to the characteristics of the lexical scope, this time the scope of each variable is already clear, and does not change with the implementation of the environment. "What does that mean?" Is that we often return a method and then execute it in another method, in which the variables in the method are scoped by the scope of the method definition. In fact, the idea here is that no matter how complex and how far you are in this method, the final judgment is whether the variable in the method can be accessed or where the method definition is to be verified.
- 3 scope (scope) Establishment rules
- A for function declarations and anonymous function expressions, [scope] is the scope at which it was created
- b for a function expression with a name, [scope] The top is a new JS object (that is, inherited Object.prototype), this object has two attributes, the first is its own name, the second is the scope of the definition, the first function name is to ensure that the code inside the function can access its own function name for recursion.
3, the implementation of the environment and activities of the object
Parsing complete, start executing code. When we call each method, the JS engine automatically creates an execution environment and an active object that is consistent with the lifecycle of the method instance, provides the necessary execution support for the method execution, and, for several of the above methods, We have set up the active object here (in the sense that the active object is generated when the method is executed, and for the sake of demonstration, the active object of all methods is defined here), as follows:
Execution Environment
- /**
- * Execution Environment: Execution environment created when function executes
- */
- var ExecutionContext = {
- window: {
- Type: "Global",
- Name: "Global",
- Body:ActiveObject.window
- },
- a:{
- Type: "Function",
- Name: "A",
- BODY:ACTIVEOBJECT.A,
- ScopeChain:this.window.body
- },
- b:{
- Type: "Function",
- Name: "B",
- BODY:ACTIVEOBJECT.B,
- Scopechain:this.a.body
- },
- c:{
- Type: "Function",
- Name: "C",
- BODY:ACTIVEOBJECT.C,
- Scopechain:this.b.body
- },
- d:{
- Type: "Function",
- Name: "D",
- BODY:ACTIVEOBJECT.D,
- Scopechain:this.b.body
- }
- }
The execution environment for each of the above methods stores information such as the type (function) of the method, the method name (FuncName), the active object (activeobject), the scope chain (Scopechain), and its key points are as follows:
- The Body property, pointing directly to the active object of the current method
- Scopechain attribute, the scope chain, which is a list structure, according to the scope attribute of the current method in the parsing tree, points to the active object (Activceobject) of the method corresponding to the scope, and the variable lookup follows the chain search.
Active Object
- /**
- * Active object: List of active objects created when function executes
- */
- var activeobject = {
- window: {
- variables:{
- I: {value:1},
- J: {Value:2},
- K: {Value:3}
- },
- functions:{
- A:this.a
- }
- },
- a:{
- variables:{
- x: {Value:4}
- },
- functions:{
- b:syntaxtree.b
- },
- parameters:{
- O: {value:10},
- P: {value:20},
- X:this.variables.x,
- Q: "Undefined"
- },
- Arguments:[this.parameters.o,this.parameters.p,this.parameters.x]
- },
- b:{
- variables:{
- y:{Value:5}
- },
- functions:{
- C:SYNTAXTREE.C,
- D:syntaxtree.d
- },
- parameters:{
- R:{VALUE:40},
- S:{VALUE:50}
- },
- ARGUMENTS:[THIS.PARAMETERS.R,THIS.PARAMETERS.S]
- },
- c:{
- variables:{
- z:{Value:6}
- },
- functions:{},
- parameters:{
- U:{VALUE:70}
- },
- ARGUMENTS:[THIS.PARAMETERS.U]
- },
- d:{
- variables:{},
- functions:{},
- parameters:{},
- Arguments:[]
- }
- }
Each of the above active objects stores the required information for the execution of the corresponding method's internal set of variables (variables), the inline function set (functions), the formal parameter (parameters), the argument (arguments), and the active object key point
- Creates an active object that replicates the internal set of variables (variables) and the inline function sets (functions) of the method from the parse tree
- Method begins execution, and the set of internal variables in the active object is reset to undefined
- Creates a formal parameter (parameters) and an argument (arguments) object with an argument of the same name, a reference relationship between a formal parameter and a variable
- Executes an assignment statement within a method, which assigns a variable to a variable set
- The variable lookup rule is first sought in the activeobject of the current execution environment, and is not found, and is looked for in the activeobject that the attribute Scopechain points to in the execution environment until the Global Object (window)
- When the method completes, the internal variable value is not reset, and when the variable is destroyed, refer to the following
- The lifetime of a variable in a method depends on whether an active reference exists in the method instance, and destroys the active object if not
- 6 and 7 are the root causes for closures to be accessible to external variables
Re-interpreting classic cases
Case 123
According to "in a method, the same name of the argument, the formal parameter and the variable is a reference relationship, that is, the JS engine processing is the same name variable and formal parameters refer to the same memory address", so there will be two of the modified arguments will affect the local variables appear
Case Four
According to the "JS engine variable lookup rule, first in the current execution environment of the activeobject search, not found, then follow the execution environment in the attribute Scopechain pointing to the activeobject to find, until the Global Object (window)", So in four, because the definition of variable i is found in the current activeobject, only the value is "undefined", so the direct output "undefined"
Summarize
The above is after I have studied and used JS for some time, in order to understand it more deeply, but also in order to better grasp the application of it, so in the closure of the learning process, their own lexical scope of some understanding and summary, there may be some places and real JS interpretation engine differences, Because I just stand in the beginning of a front-end developers rather than the system designer's perspective to analyze this problem, I hope that the JS developers understand the scope of this law to bring some help!