Scope(Scope)

Ths scope is space police that rules the accessibility variables

Scope collects and maintains declared identifiers and sets access rules,

To put it simply, scope defines the accessibility of variables. JavaScript engine can search variables in scope according to identifiers, that is, to match identifiers with variables. Meanwhile, scope isolates variables so that variables in different scopes can have the same name but different values, without affecting each other

function foo() {
  // "foo" function scope
  let count = 0;
  console.log(count); // logs 0
}

function bar() {
  // "bar" function scope
  let count = 1;
  console.log(count); // logs 1
}

foo();
bar();
Copy the code

As shown in the code above, foo and bar belong to two different scopes and both define the same variable count, but hold different values without affecting each other

Scope nesting

function outerFunc() {	// outer scope
	let outerValue = 'I am outer scope'
  
  function innerFunc() {	// inner scope
    console.log(outerValue)	// log → 'I am outer scope'
  }
  innerFunc()
}
outerFunc()
Copy the code

OuterFunc and innerFunc form two scopes, inner scope is nested within outer scope, inner scope can access variables in outer scope, resulting in the following rules:

  • Scopes can be nested
  • An outer scope can access variables in an inner scope

Lexical scope

In the traditional process of compiling a language, the source code goes through three steps called compilation before execution,

  1. Word Segmentation/Lexical Analysis (Tokenizing/Lexing)

    In this process, strings of characters are broken down into meaningful code blocks called lexical units (tokens). Var a = 2; Is decomposed into: var, a, =, 2,; . Whether or not whitespace is considered a lexical unit depends on what whitespace means in a programming language

  2. Parsing/Parsing

    This process transforms the lexical unit stream (array) into a hierarchical nested Tree of elements that represents the Syntax structure of the program, called **” Abstract Syntax Tree “(AST)**.

  3. Code generation

    The process of turning an AST into executable code is called code generation. This process depends on the language, target platform, and so on.

    The short answer is that there’s some way to set var a = 2; The AST transforms into a set of machine instructions that create a variable called A and store a finger in A

    JavaScript you Don’t Know, Volume P5

There are two types of scopes:

  • Lexical scope (or static scope)
  • Dynamic scope

Lexical scope: its scope is determined at the lexical stage, not at the excution stage. Therefore, lexical scope has a lot to do with the writing position of the code, or it can be said that lexical scope is determined by the writing position of the code

Dynamic scope: Its scope is determined at code execution time

JavaScript engines use lexical scopes

How many scopes are there in JavaScript?

  • Global scope
  • Function scope
  • Block scope: Note that block scope did not exist before ES6 (var does not have block-level scope when declaring variables), ES6 added itlet,constSuch keywords form block-level scopes in the code blocks they declare

Scope chain

The Scope Chain is the hierarchy of scopes that will be searched in order to find a function or variable.

Because scopes can be nested, when the JavaScript engine does not find a variable to use in the current Scope, it will look up to the top Scope — Global Scope. If it does not find a variable in the Global Scope, The variable is then added to the Window object (in the browser environment, and not in strict mode), and this process, like a chain, is referred to as a scope chain

Note that this repeated lookup to the upper scope is actually implemented by outer in the Lexical Environment

Lexical Environment

Identifier is a data structure that holds identity-variable mapping. Identifier refers to variable names/function names, and variable refers to references to variables (including object and function) or values of primitive types

A Lexical Environment mainly consists of two parts:

  • Environment Record: The place where variable and function declarations are stored
    • declaration Environment Record
    • Object Environment Record
    • Global Environment Record
  • Outer (Reference to the outer Environment) : Instantiated to the outer

Note: The Lexical Environment is created when the program executes

Something like the following structure:

lexicalEnvironment = {
  environmentRecord: {
    <identifier> : <value>,
    <identifier> : <value>
  }
  outer: < Reference to the parent lexical environment>
}
Copy the code

Look at a practical example:

let language = 'JS';
function a() {
  let b = 25;  
  console.log('Inside function a()');
}
a();
console.log('Inside global execution context');
Copy the code

The above code executes with two meanticists, one Global Lexical Environment and the other created by function A:

GlobalLexicalEnvironment = {
  environmentRecord: {
    language: 'JS'.a: <reference to function object>
  },
  outer: null
}
Copy the code

Note: Outer of Global Lexical Environment is null because its Lexical Environment is null for Global scope

Function A created the Lexical Environment:

FunctionLexicalEnvironment = {
  environmentRecord: {
		b: 25
  },
  outer: <GlobalLexicalEnvironment>
}
Copy the code

Function A’s outer points to the Global Lexical Environment because its code is contained within the Global scope

Execution Context

JavaScript creates an Execution Context when executing function or global code:

  • Global code: Global Execution Context
  • Function: Function Execution Context

When creating the Execution Context, the Lexical Environment is created accordingly.

As for the relationship between Lexical Scope, Execution Context and Lexical Environment, MY understanding is as follows: The creation of the latter two will actually depend on the lexical scope, as it determines the accessibility of the identifiers, which in turn is related to the creation of the lexical Environment (related to outer).

About how the JavaScript engine handles execution context:

  1. When the JavaScript engine executes code in the global scope, creates a Global Execution Context and adds itExecution Context Stack(also called: Call Stack), and set it toRunning Lexical Environment
    1. When Global Execution Context is created, the Global Lexical Environment is also created, and the Lexical Environment does two main things: Implement Environment Record(binding of identifiers to variables) and outer pointing (pointing to the outer lexical Environment, in the Global Execution Context, outer pointing to NULL)
  2. When the function is executed, creates a Function Execution Context for the current Function and adds it to the Execution Context Stack, setting it to running Execution Context
    1. Creating a Function Execution Context does the same thing as creating a Global Execution Context, except that outer points to the Global Execution Context (PS: Nested calls to functions are also nested in lexical scopes.
  3. When the Function Execution is complete, the Function Execution Context of the current Function is removed from the Execution Context Stack and destroyed. Also set the Global Lexical Environment to the Running Lexical Environment

Note: The above procedure only considers the absence of nested functions, which are similar

Pay attention to

  • There are many differences between the Specification of ES5 and the Specification of ES6, and no distinction has been made above

  • Some of the things described above are omitted, for example:

    • Execution Context consists of not only Lexical Environment, but also Variable Environment and PrivateEnvironment.

    • The type of Environment Record can be: Declaration Environment Record, Object Environment Record and Global Environment Record The standard explicitly states that the Environment Record has [outer], which is used to refer to the outer Environment Record, whereas in our description above, the [outer] field is in the Lexical Environment, It has the same relationship with Environment Record, including most articles on the Internet, which are described in this way, but it seems to be inconsistent with the standard, I wonder whether there is a misunderstanding of the standard? A: This is mainly because ECMA-262 5.1 Edition and ECMA-262 12th Edition are different. 5.1 is released in 2011, and 12th Edition is the latest Edition in 2021. For the description of Lexical Environment in 5.1, no detailed description of Lexical Environment is found in 12th, but only the description of Environment Record

confusion

  • Lexical Scope is determined at the Lexical analysis stage, while Execution Context and Lexical Environment are created at the Execution stage. Is the creation of the Execution Context and Lexical Environment dependent on the Lexical Scope? From what we’ve learned so far, it looks like it is
  • The terms Scope and Lexical Scope and their implementations are not mentioned in the specification of ECMAScript262. Is it because Scope generation is an essential routine operation during code compilation and execution that it is not mentioned in the specification? According to the concept of scope, Lexical Environment is most relevant to it in the specification. Is it the concrete realization of scope?

Reference:

  • Understanding Scope and Scope Chain in JavaScript

  • Scope Chain & Lexical Environment in Javascript

  • Execution Context in Javascript

  • Executable Code and Execution Contexts

  • Ecma262 5.1 th