Skip to content
字数
1112 字
阅读时间
5 分钟

概述

执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念

执行栈

也叫调用栈,具有 IFLO(先进后出)的结构,用于存储代码执行期间创建的所有执行上下文

当 JS 引擎 首次读取 js 代码时,会首先创建一个全局执行上下文压入执行栈中,当发生函数调用时,又会为函数创建一个函数执行栈压入执行栈中,当该函数执行完成,就会从执行栈中弹出

类型

全局执行上下文

默认的、最基础的执行上下文,不在任何函数中代码都位于全局执行上下文中

创建过程:

  1. 创建一个全局对象,在浏览器中这个全局对象就是 window 对象
  2. this 指向这个全局对象

一个程序只能存在一个全局执行上下文

函数执行上下文

每次 调用 函数时,才会为该函数创建一个函数执行上下文。每个新的函数执行上下文被创建,都会按照 执行栈 的顺序进行执行

一个程序可以存在多个函数执行上下文

Eval 函数执行上下文

运行在 eval 函数中的代码也获得了自己的执行上下文

执行栈举例

js
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');

执行栈中的流程图:

创建过程

执行上下文的创建分为两个阶段:1.初始化阶段 2.执行阶段

初始化阶段

在这一阶段,需要做三件事情:

  1. 确定 this 的值,也就是 This Binding
  2. 创建 LexicalEnvironment (词法环境
  3. 创建 VariableEnvironment (变量环境

This Binding

全局执行上下文中, this 指向全局对象——window 对象
函数执行上下文中,this 指向调用者

词法环境

  • 环境记录:存储变量和函数声明的实际位置
  • 对外部环境的引用:意味着可以访问其外部词法环境

在函数执行上下文中,环境记录还包含了一个 arguments 对象,表示函数参数的相关属性

js
function foo(a, b) {  
  var c = a + b;  
}  
foo(2, 3);

// arguments 对象  
Arguments: {0: 2, 1: 3, length: 2},

在全局执行上下文中,对外部环境的引用为 null

变量环境

它也是一个词法环境,其 EnvironmentRecord 包含了由 VariableStatements 在此执行上下文创建的绑定

如上所述,变量环境也是一个词法环境,因此它具有上面定义的词法环境的所有属性。

在 ES6 中,LexicalEnvironment 组件和 VariableEnvironment 组件的区别在于前者用于存储函数声明和变量( letconst )绑定,而后者仅用于存储变量( var )绑定。

初始化阶段举例

js
let a = 20;  
const b = 30;  
var c;

function multiply(e, f) {  
 var g = 20;  
 return e * f * g;  
}

c = multiply(20, 30);

执行上下文如下所示:

js
GlobalExectionContext = {

  ThisBinding: <Global Object>,

  LexicalEnvironment: {  
    EnvironmentRecord: {  
      Type: "Object",  
      // 标识符绑定在这里  
      a: < uninitialized >,  
      b: < uninitialized >,  
      multiply: < func >  
    }  
    outer: <null>  
  },

  VariableEnvironment: {  
    EnvironmentRecord: {  
      Type: "Object",  
      // 标识符绑定在这里  
      c: undefined,  
    }  
    outer: <null>  
  }  
}

FunctionExectionContext = {  
   
  ThisBinding: <Global Object>,

  LexicalEnvironment: {  
    EnvironmentRecord: {  
      Type: "Declarative",  
      // 标识符绑定在这里  
      Arguments: {0: 20, 1: 30, length: 2},  
    },  
    outer: <GlobalLexicalEnvironment>  
  },

  VariableEnvironment: {  
    EnvironmentRecord: {  
      Type: "Declarative",  
      // 标识符绑定在这里  
      g: undefined  
    },  
    outer: <GlobalLexicalEnvironment>  
  }  
}

执行阶段

在此阶段,完成对所有变量的分配,最后执行代码

执行上下文与作用域的区别

作用域是在函数声明时就确定的一套变量的访问规则,而执行上下文是函数执行时才产生的一系列变量的环境。

也就是说,作用域定义了执行上下文中的变量的访问规则,执行上下文在这个作用域规则的前提下进行变量查找,函数引用等具体操作

转载

【译】理解 Javascript 执行上下文和执行栈

贡献者

The avatar of contributor named as jiechen jiechen

页面历史

撰写