This is the fifth day of my participation in the August More text Challenge. For details, see: August More Text Challenge

I. Execution Context (EC)

When the JavaScript code executes a executable code, it creates an execution context that is understood to be an object.

When executing JS code, there are three execution contexts:

  • Global execution context
  • Function execution context
  • Eval execution context

Each execution context has three important properties:

  • A Variable object (VO), when entered in an execution context, has not yet executed code. A Variable object contains variables, function declarations, and function parameters. This property can only be accessed in a global context
  • Scope chain. JS uses lexical Scope, which means that the Scope of a variable is determined when it is defined
  • this

Execution context Stack (ECS)

To manage the Execution context, the JavaScript engine creates an Execution context Stack (ECS).

2.1 a

var a = 10;
function foo(i) {
  var b = 20;
}
foo();
Copy the code

For the above code, there are two contexts in the execution stack: the global context and the function foo context.

When JavaScript begins to interpret execution code, the first thing it encounters is global code, so initialization first pushes a global execution context onto the execution context stack, which we represent as globalContext, and only when the entire application ends, The stack will be cleared.

stack = [ globalContext, fooContext]
Copy the code

For global context, VO looks something like this:

globalContext.VO === globe
globalContext.VO = {
  a: undefined.foo: <Function>,}Copy the code

For function foo, VO cannot access it, only to the active object (AO)

// Arguments is a function unique object (arrow function does not)
// The object is a pseudo-array with a 'length' attribute and elements can be accessed by subscript
// The 'callee' property in the object represents the function itself
// The 'caller' attribute represents the caller of the function
fooContext.VO === foo.AO
fooContext.AO = {
  i: undefined.b: undefined.arguments: <>
}

Copy the code

In the case of a Scope chain, you can think of it as a list of its own variable objects and its parent variable objects. The parent variable is found by the [[Scope]] property

fooContext.[[Scope]] = [
  globalContext.VO
]

fooContext.Scope = fooContext.[[Scope]] + fooContext.VO

// so
fooContext.Scope = [
  fooContext.VO,
  globalContext.VO
]
Copy the code

2.2 the second

function fun3() {
  console.log("fun3");
}
function fun2() {
  fun3();
}
function fun1() {
  fun2();
}
fun1();
Copy the code

When a function is executed, an execution context is created and pushed onto the execution context stack. When the function finishes executing, the execution context of the function is popped off the stack. Now that we know how this works, let’s take a look at how to handle the above code:

/ / pseudo code

// fun1()
ECStack.push(<fun1> functionContext);
// ECStack = [globalContext, fun1Context]

// Fun2 is called in fun1, and the execution context of fun2 is created
ECStack.push(<fun2> functionContext);
// ECStack = [globalContext, fun1Context, fun2Context]

// Wipe, fun2 also calls fun3!
ECStack.push(<fun3> functionContext);
// ECStack = [globalContext, fun1Context, fun2Context, fun3Context]

// fun3 Finish
ECStack.pop();
// ECStack = [globalContext, fun1Context, fun2Context]

// fun2 Complete
ECStack.pop();
// ECStack = [globalContext, fun1Context]

// fun1 Finish
ECStack.pop();
// ECStack = [globalContext]

// Javascript then executes the following code, but there is always a globalContext at the bottom of the ECStack
Copy the code