Prepend content
Js – Scope chain
Scope: Is responsible for collecting and maintaining a series of queries made up of all declared identifiers (variables) and enforcing a very strict set of rules that determine access to these identifiers by currently executing code.
The environment in which the code is currently running, accessible variables, and variable environment objects on the scope chain.
What is an execution context
In short, an execution context is an abstraction of the context in which JavaScript code is evaluated and executed. Whenever Javascript code is running, it is running in an execution context.
Execution context is the concept of a scenario, an environment, in which code is run. Just like Chinese culture is extensive and profound. The same sentence may have two different meanings and senses in different situations.
The type of execution context
- Global execution context – This is the default or base context, and any code that is not inside a function is in the global context. It does two things: it creates a global Window object (in the case of the browser) and sets the value of this to equal the global object. There is only one global execution context in a program.
- Function execution Context – Each time a function is called, a new context is created for that function. Each function has its own execution context, but is created when the function is called. There can be any number of function contexts. Each time a new execution context is created, it performs a series of steps in a defined order (discussed later).
- Eval function execution context – Code executed inside the Eval function also has its own execution context, but Eval is not often used by JavaScript developers.
Execution stack
The JavaScript engine creates an Execution Context stack (ECS) to manage the Execution context Execution stack, or “call stack” in other programming languages, which is a stack with LIFO (LIFO) data structures, Is used to store all execution contexts created when the code is run. When the JavaScript engine first encounters your script, it creates a global execution context and pushes it onto the current execution stack. Every time the engine encounters a function call, it creates a new execution context for that function and pushes it to the top of the stack. The engine executes functions whose execution context is at the top of the stack. When the function completes execution, the execution context pops out of the stack and the control flow moves to the next context in the current stack.
How do I create an execution context?
- The determination of the this value, known as the This binding.
- Create the lexical environment component.
- Create the variable environment component.
A lexical environment specifies a lexical environment object that is used to resolve identifier references created by code within that execution environment. A variable environment specifies a lexical environment object whose environment data is used to hold bindings created by code within that execution environment through variable and function expressions. The This binding specifies the value associated with the This keyword in the ECMA script code within the execution environment.
Where the lexical environment and variable environment components of the execution environment are always lexical environment objects. When you create an execution environment, the lexical environment component and the variable environment component start with the same value. The variable environment component never changes during the execution of the code associated with the execution environment, while the lexical environment component may change.
Lexical environment
A lexical environment is a canonical type that defines the associations of identifiers and concrete variables and functions based on the lexical nesting structure of ECMAScript code. A lexical environment consists of an environment logger and a null value that may reference an external lexical environment.
Simply put, a lexical environment is a structure that holds identity-variable mappings. (The identifier here refers to the name of the variable/function, and the variable is a reference to the actual object [containing the object of the function type] or the original data). Now, inside the lexical environment there are two components :(1) the environment logger and (2) a reference to the external environment.
- The environment logger is the actual location where variable and function declarations are stored.
- A reference to an external environment means that it has access to its parent lexical environment (scope).
Environment loggers also come in two types (as above!) Declarative environment loggers store variables, functions, and parameters. The object environment logger is used to define the relationship between variables and functions that appear in the global context. In short,
- In a global environment, the environment logger is the object environment logger.
- In a functional environment, the environment logger is the declarative environment logger.
GlobalExectionContext = {
LexicalEnvironment: {
EnvironmentRecord: {
Type: "Object".// Bind the identifier here
}
outer: <null>
}
}
FunctionExectionContext = {
LexicalEnvironment: {
EnvironmentRecord: {
Type: "Declarative".// Bind the identifier here
}
outer: <Global or outer function environment reference>}}Copy the code
The variable environment
It is also a lexical environment whose environment logger holds bindings created in the execution context of variable declaration statements.
As mentioned above, the variable environment is also a lexical environment, so it has all the attributes of the lexical environment defined above.
In ES6, one difference between a lexical environment component and a variable environment is that the former is used to store function declarations and variable (let and const) bindings, while the latter is used only to store var variable bindings.
let a = 20;
const b = 30;
var c;
function multiply(e, f) {
var g = 20;
return e * f * g;
}
c = multiply(20.30);
Copy the code
GlobalExectionContext = {
ThisBinding: <Global Object>, LexicalEnvironment: {EnvironmentRecord: {Type: "Object", < uninitialized >, multiply: < func > } outer: <null> }, VariableEnvironment: { EnvironmentRecord: { Type: } outer: <null>}} FunctionExectionContext = {ThisBinding: <Global Object>, LexicalEnvironment: {EnvironmentRecord: {Type: "Declarative", // 30, length: 2}, }, outer: <GlobalLexicalEnvironment> }, VariableEnvironment: { EnvironmentRecord: { Type: G: undefined, outer: <GlobalLexicalEnvironment>}}Copy the code
Conclusion:
Identifier explanation:
An identifier is the name of a variable, function, attribute, or function parameter. An identifier can consist of one or more of the following characters:
- The first character must be a letter, underscore (_), or dollar sign ($);
- The remaining characters can be letters, underscores, dollar signs, or numbers.
The letters in the identifier can be Extended ASCII, or Unicode alphabetic characters, such as A and æ is not recommended.
Execution context
- The determination of the this value, known as the This binding.
- Create the lexical environment component.
- Create the variable environment component.
The difference between lexical and variable contexts
- A lexical environment specifies a lexical environment object that is used to resolve identifier references created by code within that execution environment.
- A variable environment specifies a lexical environment object whose environment data is used to hold bindings created by code within that execution environment through variable and function expressions.
- The This binding specifies the value associated with the This keyword in the ECMA script code within the execution environment.
Where the lexical environment and variable environment components of the execution environment are always lexical environment objects. When you create an execution environment, the lexical environment component and the variable environment component start with the same value. The variable environment component never changes during the execution of the code associated with the execution environment, while the lexical environment component may change.
function test(a) {
var a = 1;
let b = 2;
var name = '123';
var c = {
name: 'rod'
}
c.name = 'rodchen'
with(c) {
console.log(name)
}
}
test(123)
Copy the code
Lexical environment often with specific ECMAScript code such as FunctionDeclaration, WithStatement or TryStatement Catch block such grammatical structure, And a new syntax environment is created each time similar code is executed. When implementing with, the lexical environment is different
graphic
The difference between execution context and scope:
This part comes from this question that members asked me.
Different creation times
- A scope is created when a function is created
- The execution context is created while the function is running
Different creators
- The scope is lexically created, static
- The execution context is created dynamically by the JS engine
Ranking explain
- Engine: Responsible for compiling and executing Javascript programs from start to finish
- Compiler: One of the engine’s best friends, responsible for parsing and code generation
- Scope: Another good friend of the engine, responsible for collecting and maintaining a series of queries made up of all declared identifiers (variables) and enforcing a very strict set of rules that determine the access to these identifiers by currently executing code
The connection between the two
For example,
var a = 2; Compiler: Breaks the program down into lexical units, which are then parsed into a tree structure.
- For var a, the compiler checks to see if a variable of that name already exists in the collection of scopes. If so, the compiler ignores the declaration and continues compiling. Otherwise, it will require the scope to live a new variable in the collection of the current scope and name it a;
- The compiler then generates run-time code for the engine to handle the assignment of a = 2. The engine starts by asking the scope if there is a variable called A in the current set of scopes. If not, the engine uses this variable; If it’s not, the engine will keep looking for that variable and if the engine finally finds a variable, it will assign 2 to it. Otherwise the engine will throw an exception!
Conclusion: Assigning a variable performs two actions. First, the compiler declares a variable in the current scope (if it hasn’t been declared before), and then at runtime the engine looks for the variable in the scope and assigns it if it can find it.
Compiler noun explanation:
LHS(Left Hand Side) : AN LHS query tries to find the container itself for a variable so that it can be assigned a value
RHS(Right Hand Side): RHS queries on the right hand side are the same as simply looking up the value of a variable. RHS is not really “the right hand side of an assignment operation”, but rather “not the left hand side”. RHS can be understood as retrieve his source value.
function foo(a) {
// There is an implicit I step: a = 2;
var b = a;
return a + b;
}
var c = foo( 2 );
Copy the code
Here’s the conversation:
- Engine: Scope brother, I need to do LHS on C, you know?
- Scope: I know, here you go.
- Engine: WHEN I say scope, I need to make an RHS reference for Foo. Have you seen it?
- Scope: No, I’ve actually seen it. The compiler guy just declared it. It’s a function. Here you go.
- Engine: Dude too interesting! All right, so let me execute foo.
- Engine: scope, there’s another thing. I need to make LHS reference for A, have you seen this?
- Scope: I’ve seen this before, but the compiler recently named it as a formal parameter to foo, so take it.
- Engine: Thanks, you’re always great. Now I’m going to assign 2 to A.
- Engine: scope, I need to LHS on a, please give me this value!
- Scope: Ok, I get it. Here you go.
- Engine: scope, I need to RHS a, I’m sure you know.
- Role: Sure, here you go.
- Engine: OK, thank you, now I’m going to assign a value.
- Engine: I have one more step, I need to RHS AB.
- Scope: Yes, here you are.
- Engine: Execute code return a + b; Once you have the structure of function, execute the assignment statement.
conclusion
The execution context needs to work with the scope otherwise the work cannot be done. Based on the description of the lexical environment above, you can also see the execution context’s reference to the scope. The lexical context of the execution context can be understood as the JS scope.
A reference to the external environment means that it has access to its parent lexical environment (scope)