This is the sixth day of my participation in Gwen Challenge
First of all, we know that JS is interpreted language, including two stages of interpretation stage, implementation stage.
- In the interpretation stage, the interpreter performs lexical analysis, grammar analysis and scope rule determination.
- The execution phase, which is executed by the JS engine, creates context, executes code, and garbage collection.
scope
As mentioned earlier, JS determines scope rules at the interpretation stage. So what is scope?
A scope is the set of variables, functions, and object accessibility in runtime code [1].
Scope can be divided into lexical scope (static scope) and dynamic scope.
Dynamic scope does not care where functions are declared, only where they are called from. Static scopes can be identified at writing time. In short, lexical scope is determined at definition time, while dynamic scope is determined at run time. JS uses static scope. In fact, dynamic scope is the embodiment of another important JS mechanism, this. Some people confuse scopes mostly because static scopes are confused with the dynamic this mechanism. So why is this dynamic? This is explained later.
var a = 2;
function foo() {
console.log( a );
}
function bar() {
var a = 3;
foo();
}
bar();//2 Because foo is defined in the global environment
Copy the code
Put foo inside the bar function:
var a = 2;
function bar() {
var a = 3;
function foo() {
console.log( a );
}
foo();
}
bar();//3 Because foo is defined in the context of bar functions
Copy the code
The scope chain
Scope chain is essentially a pointer to the variable object list, position the pointer list the zeroth always are currently executing code in the environment, pointing to the next position definition contains the environment, the next position point to the next definition contains the environment, so until the end of the scope of the global environment. Identifier parsing is the process of finding identifiers level by level through the scope chain.
Execution context
An execution context is the environment in which JavaScript executes a piece of code. When a program encounters executable code, it enters an execution context, which is a logical stack structure. The top execution context in the stack is the execution context that is running. Each execution context has a variable environment, a lexical environment, and this.
When JS initializes a global or executes a function (the JS execution phase) :
- The context is created first. There are two types of execution context: global execution context and function execution context.
- It then pushes the created context onto the call stack, executes the code, and pops out of the call stack.
- Recycling.
The execution context life cycle can be divided into creation stage and execution stage
Creation phase:
-
The variable environment and lexical environment are defined.
-
Determine what this points to (so this is not determined until execution).
-
Establish scope chains.
Variable environment: This is where variables declared by var are stored
Lexical environment: Variables declared by let, const, with(), try-catch, and function exist here.
Lexical environment consists of two parts: environmental record and introduction record to external environment. The global context is not the same as the function context’s external environment import record, the global is null, the function is the global environment or other function environment. The environment record is also different. The global is called object environment record, and the function is called declarative environment record.
A lexical environment is a specification type that defines the relationship between identifiers and specific variables and functions in ECMAScript code. The lexical environment, on the other hand, contains an environment record and a reference to the external lexical environment, which may be null.
Execution phase: Variable assignment, function reference.
this
The reference to this is determined when the context is created, which is different from the static scope of JS. This refers to the execution environment in which the execution is performed. There are no more than five directions:
Call way | example | Point to the |
---|---|---|
Function direct call | xxx() | window |
Calling a | a.b() | a |
The new call | new xx() | A new object |
Arrow function call | () = > {} | The parent environment |
Explicitly call | Call (xx), apply(xx), bind(xx) | xx |
function foo(){
console.log(this)};let a = 2;
let obj = {
a:1.fn1:foo,
fn2:() = >{
console.log(this)}};let exe1 = obj.fn1;
let exe2 = obj.fn2;
exe1();//this=>window
exe1.call(a);//this=>Number {2}
exe1.call(obj.a);//this=>Number {1}
exe1.call(obj.fn1);//foo
obj.fn1();//this=>obj
obj.fn1.call(a);//this=>Number {2}
obj.fn1.call(obj.a);//this=>Number {1}
obj.fn1.call(obj.fn1);//this=>foo
exe2();//this=>window
exe2.call(a);//this=>window
exe2.call(obj.a);//this=>window
exe2.call(obj.fn1);//this=>window
// Arrow function this cannot be changed
obj.fn2();//this=>window
obj.fn2.call(a);//this=>window
obj.fn2.call(obj.a);//this=>window
obj.fn2.call(obj.fn1);//this=>window
// Arrow function this cannot be changed
Copy the code
This is basically, you want this function to be executed in any environment, you want it to be executed in the Window environment, you just execute it; If you want to execute in an object’s environment, you execute as if it were a property of the object. To customize the execution environment, use Call, apply, and bind.
Before a function is executed, the function’s this can refer to any environment, so when you write a function, stop worrying about who this refers to. When you call it, you can refer to whomever you want.
The call stack
With so many execution contexts, how do you manage them? This brings us to the execution context stack.
The stack that houses and manages the execution context is called the call stack.
You can think of a global execution context at the bottom of the execution stackThere is always a global execution context at the bottom of the stack unless the program is stopped or the browser is closed.
closure
I prefer to say that closures are a combination of functions and the lexical environment in which they are declared. The term comes from MDN. Closures are not a function, but a combination of functions and lexical environments. In the closure scenario, a function does have access to variables in another function’s scope, but a closure is not a function.
Another way of saying it is that a closure is a function that has access to a variable in the scope of another function.
conclusion
The difference between scoped chain and prototype chain
When accessing a variable, the interpreter first looks in the current scope. If it does not find a variable, the interpreter looks in the scope in which the function was created. The top of the scope chain is the global object Window.
When a property is accessed on an object, it looks for the current object. If not, it looks up the prototype chain. The top of the prototype chain is null, and if not, it returns undefined instead of an error.
Variable object (VO)/ Active Object (AO)
When you read other articles about execution context, you must wonder if the execution context creation process should explain this, scope, and variable objects/active objects.
These keywords are not found when reading the ECMAScript specification. Reference can be found that the concept of variable object and active object is an old concept proposed in ES3. Since ES5, lexical environment and variable environment have been replaced.
The concept of a lexical environment corresponds to a variable object: a variable object (VO) and an active object (AO) are actually variable objects. A variable object is an execution context-specific data scope that stores variable and function declarations defined in the context. In the functional context, we use active objects (AO) to represent variable objects, which corresponds to the lexical context.
And since ES6’s new let const does not have variable promotion, the concept of lexical and variable environments is explained.
Reference:
Unpacking closures, this time from the ECMAScript lexical context, the execution context
An article to understand the JS execution context
Detailed explanation of execution contexts, scope chains, and closures in JavaScript