For the implementation mechanism of Javascript understanding is relatively shallow, just recently saw Li Bing teacher browser course (have to pay yo), understand the implementation mechanism of Javascript, for variable improvement, temporary dead zone understanding can be deepened, but also can preliminary copy out of the code execution.

showName()
console.log(myName)
var myName = 'Stop it, Kobayashi.'
console.log(yourName)
let yourName = 'Go Xiao Lin'
function showName() {
    console.log('function showName is executed');
}
Copy the code

If you are also confused or interested in the results of the above code, read on

1. Compile

First, you can make it clear that the code is compiled before it is executed

The process of compilation is complicated, I am not very clear, interested friends can learn, and then tell me (laugh), quoting a paragraph of Teacher Li Bing’s words

Compilation generates bytecode, which the interpreter can then execute directly, producing results. But Javascript usually has a compiler that compiles the frequently executed bytecode into binary so that frequently run functions can be executed quickly. This technique of mixing the interpreter and compiler is often called JIT

For the time being, we can divide the compilation of this code into two parts: the execution context and the executable code

Var myName = ‘kobayashi’ var myName = ‘kobayashi’ var myName = ‘kobayashi

var myName    // The declaration part
myName = 'Stop it, Kobayashi.'  // The assignment part
Copy the code

1.1 Execution Context

There are three types of execution contexts:

  • Global execution context: Only one, created when the program is first run and held at the bottom of the call stack until the program finishes running

  • Function execution context: Created when a function is called, a new execution context is created for the function each time it is called, regardless of whether the function is called repeatedly

  • Eval execution context: The execution context created when the code in the Eval function is run. Rarely used and not recommended. I’m not sure

The execution context can be provisionally understood as consisting of two objects: **** variable environment and lexical environment

The compiled execution context of the code at the beginning of the article looks like this:

At compile time, the JavaScript engine refers the declared parts of variables and functions declared by var to the variable environment object, given the default value undefined. The JavaScript engine finds a function defined by function, so it stores the function definition in the HEAP and creates a showName property in the environment object

The declaration section for variables declared by lets and const refers to the lexical environment object, which is managed by a stack structure. Also give the default value undefined. When the execution context is not switched, variables declared with let and const create a new lexical environment when a new block scope is encountered. The newly created lexical environment is pushed onto the stack and destruction is popped at the end of the associated statement.

1.2 Executable code

After compiling, the code is executed, line by line. The execution code looks like this:

showName()// The function declaration is promoted to the variable environment, so it can be executed.
console.log(myname)//var defines variables that are also promoted to the variable environment and default to undefined, so undefined is printed
myname = 'Stop it, Kobayashi.'// Change the value of myname in the variable environment to "Kobayashi stop"
console.log(yourName)// Let defined variables in the lexical environment default to undefined, but javascript does not allow let defined variables to be used before declaration, so an error is reported
Copy the code

Is it clear what the result of the code at the beginning of the article is

2. The call stack

Functions are compiled only when they are called. When a function is called, it has a new execution context, which is managed through a stack structure that manages the calling relationships between functions. This stack is called the call stack, and the code at the beginning of this article actually has two execution contexts. When the showName function finishes executing, the execution context is removed from the call stack.

2.1 stack overflow

The size of the stack is finite, and exceeding the stack size will cause stack overflow, such as recursive calls

// function foo(){
// return setTimeout(foo, 0);
/ /}
function foo(){
    return foo();
}
foo()
Copy the code

The reason setTimeout is able to avoid stack overflow is that setTimeout is asynchronous and is given to Web API. When the time is triggered, the callback functions are sent to the task queue. The event loop constantly monitors the task queue and processes the callbacks one at a time in the order they are queued. Whenever the call stack is empty, the event loop gets the callback and puts it on the stack for processing. Remember that if the call stack is not empty, the event loop does not push any callbacks onto the stack.

Alternatively, you can set a variable depth to indicate the number of levels of the call, and terminate the recursion when it exceeds a certain number of levels

3. Scope chain

When writing code, if you use a variable that does not exist in the current scope, the JavaScript engine needs to look for the variable in other scopes along the scope chain

This is because the scope chain of the JavaScript language is determined by the lexical scope, which is determined by the structure of the code, that is, where functions are declared in the code

The order of the call stack is the order of the function call. Between the execution contexts, the search for variables is along the scope chain. The order of scope has nothing to do with the order of the call, only with the order of the declaration

var a = 'A'
let b = "B"
let c = "C"
function foo() {
    console.log( a ); 
}
function bar() {
    var a = "a";
    foo();
    console.log(c)
    let c = "c" 
}
bar();

Copy the code

The results are as follows:

foobarFunctions are declared in the global scope, and when they look for variables along the scope chain, of course they find the global execution context, but in thebarInside the functionletThe statementcsobarWhat you find is in your lexical environmentcHowever, the Javascript engine does not allow it to be called before assignment, so an error is reported. The following diagram should be drawn wrong (cry). In the lexical context of the execution context of the bar function,cShould stillundefinedThe following code should not be executed because of an error.

By the way, there are a lot of things in the execution context, as shown below:

The outer is a reference to the outer execution up and down, along the scope chain, regardless of the call

In non-strict mode, all normal functions are Windows. Of course, you can remember that this always points to the caller. Our arrow functions don’t have this, they are external

Reference:

8 Questions to see if you really know JS

How browsers work and practice