JavaScript复习-JavaScript的执行过程

2021-05-28 02:22:062024-04-03 20:36:52

JavaScript 代码在执行时,首先创建一个全局可执行上下文(GlobalContext,每当执行到一个函数调用时都会创建一个可执行上下文(ExecutionContext)EC。当然程序可能存在很多函数调用,那么就会创建很多 EC,所以 JavaScript 引擎创建了执行上下文栈(ExecutionContextStack)ECS来管理执行上下文。当函数调用完成,JavaScript 会退出这个执行环境并把这个环境销毁,回到上一个执行环境...。这个过程反复执行,直到执行栈中的代码全部执行完毕。

执行上下文栈

可以借助以下代码理解

let a = "Hello World!";

function first() {
  console.log("Inside first function");
  second();
  console.log("Again inside first function");
}

function second() {
  console.log("Inside second function");
}

first();
console.log("Inside Global Execution Context");

ecs

执行上下文

简而言之,执行上下文就是对当前js代码被解析和执行所依赖的环境的抽象概念,执行上下文包含了当前执行的代码、变量和函数等信息。

执行上下文的创建阶段主要负责三件事:

  1. this
  2. Lexical Environment
  3. Variable Environment

词法环境

js采用的是词法作用域(静态作用域),因此代码的书写顺序/位置决定了作用域

词法环境(Lexical Environment):作用于词法分析阶段。包含两部分:

  1. Environment Record(环境记录)是一个以全部局部变量为属性的对象(以及其他如 this 值的信息)。
  2. 对 outer lexical environment(外部词法环境)的引用,通常关联词法上的外面一层代码(花括号外一层)。

Environment Record 包含两种类型 声明性环境记录对象环境记录 。后者出现在全局词法环境中。

词法环境是在代码定义的时候决定的,跟代码在哪⾥调⽤没有关系

// 全局执⾏上下⽂
GlobalExecutionContext = {
  // 词法环境
  LexicalEnvironment: {
    // 环境记录
    EnvironmentRecord: {
      Type: "Object", // 全局环境
      // ... 标识符绑定在这⾥
      outer: <null>, // 对外部环境的引⽤
    }
  }
}
// 函数执⾏上下⽂
FunctionExecutionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",// 函数环境
      // ... 标识符绑定在这⾥
      // 对全局环境或外部函数环境的引⽤
      outer: <Global or outer function environment reference>,
    }
  }
}

词法环境与闭包

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure) --MDN

变量环境

为了继续去适配早期 JavaScript 的var等,ES6 增加了变量环境(Variable Environment)。变量环境也是一个词法环境,其环境记录器包含有变量声明语句

在 ES6 中,词法环境和变量环境的区别在于前者用于存储函数声明和变量(letconst)绑定,而后者仅用于存储变量(var)绑定,同时变量环境同时会将变量初始化为 undefined 这就是 变量提升

示例

let a = 20;
const b = 30;
var c;
function multiply(e, f) {
  var g = 20;
  return e * f * g;
}
c = multiply(20, 30);

词法构成

// 全局执⾏上下⽂
GlobalExecutionContext = {
  ThisBinding: < Global Object > ,
  // 词法环境
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // 标识符绑定,let、const、函数声明
      a: < uninitialized > ,
      b: < uninitialized > ,
      multiply: < func >
    }
    outer: < null >
  },
  // 变量环境
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // 标识符绑定,var 声明
      c: undefined,
    }
    outer: < null >
  }
}

// 函数执⾏上下⽂
FunctionExecutionContext = {
  ThisBinding: < Global Object > ,
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // 标识符绑定
      Arguments: {
        0: 20,
        1: 30,
        length: 2
      },
    },
    outer: < GlobalLexicalEnvironment >
  },
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // 在这⾥绑定标识符
      g: undefined
    },
    outer: < GlobalLexicalEnvironment >
  }
}

参考

MDN-闭包

JS | 执行调度过程

理解 Javascript 执行上下文和执行栈