likes
comments
collection
share

js核心系列(二) —— 彻底理解js执行上下文

作者站长头像
站长
· 阅读数 15

js核心系列(二) —— 彻底理解js执行上下文

什么是js执行上下文(Execution Context)

有的人说,执行上下文是指一个环境的抽象概念,在这个环境中可以计算和执行 Javascript 代码,JavaScript中的代码,都是在执行上下文中运行的。

有的人说,执行上下文包含了跟踪对应可执行代码执行进度所需要的所有状态,每个执行上下文中都有特定的实体对象用于记录这些特定状态。

有的人说,执行上下文是指当前执行环境中的变量、函数声明,参数(arguments),作用域链,this等信息。

GPT3.5说 :执行上下文是指一个执行环境,它负责管理 JavaScript 代码的执行状态和内存资源。

GPT4说: JS执行上下文是JavaScript代码运行时的环境,它决定了变量的作用域、函数的调用和对象的访问。

那么多概念,你可能难以记住。简而言之,我们就只需要记住:执行上下文是运行JavaScript代码的环境

执行上下文有那些

执行上下文主要有2种,

  • 全局执行上下文(Global Execution Context)
  • 函数执行上下文(Function Execution Context)

全局执行上下文 Global Execution Context (GEC)

全局执行上下文的概念

全局执行上下文只有一个,在客户端中一般由浏览器中的js引擎创建。所有不在函数内部的JavaScript代码都会在其中执行。全局执行上下文是一个特殊的执行上下文,它在整个JavaScript 程序执行期间都是存在的,所以对于每个JavaScript 文件,只能有一个全局执行上下文

全局执行上下文产生时间

看过上一篇文章js核心系列(一)——v8引擎解析原理的同学应该就知道了,当 V8引擎接收到一段可执行代码前,会准备执行JavaScript时所需要的一些基础环境,其中就包括全局执行上下文。V8 用执行上下文来维护执行当前代码所需要的变量声明、this 指向等

函数执行上下文 Function Execution Context (FEC)

函数执行上下文概念

函数执行上下文理论上可存在无数个,每当一个函数被调用时都会创建一个函数执行上下文,需要注意的是,同一个函数被多次调用,都会创建一个新的上下文。

创建执行上下文的两个阶段

前面已经说了什么是执行上下文以及不同种类的执行上下文(全局上文和函数上下文),现在让我们来看看执行上下文是如何被创建的。

执行上下文(GEC或FEC)的创建分为两个阶段

  1. 创建阶段(Creation Phase)
  2. 执行阶段(Execution Phase)

创建阶段(creation phase)

早期ECMA的版本规范:

我们还是首先了解一下早期的流程,早期在创建阶段被分为3个阶段,在这3个阶段中定义和设置执行上下文对象的属性。这些阶段是:

  • 创建对象(Global Object,variable object)

js核心系列(二) —— 彻底理解js执行上下文

  • 作用域链(scope chain)的创建
  • 设置 this 关键字绑定

最新的ECMA的版本规范中

js核心系列(二) —— 彻底理解js执行上下文

在最新的ECMA标准中,对于一些词汇进行了修改

最新规范的全局执行上下文中主要包含了三部分,变量环境、词法环境、和 this 关键字的绑定

js核心系列(二) —— 彻底理解js执行上下文

比如我们可以直接在控制台打印this, window等。这些就是在全局上下文中包含的。

我们可以以对象的形式来加强理解

GlobalExecutionContext = {
    LexicalEnvironment: {},
    VariableEnvironment: {},
}

LexicalEnvironment(词法环境)

ECMAScript规范中对词法环境的描述如下:词法环境是用来定义 基于词法嵌套结构的ECMAScript代码内的标识符与变量值和函数值之间的关联关系 的一种规范类型。一个词法环境由环境记录(Environment Record)和一个可能为null的对外部词法环境的引用(outer)组成。一般来说,词法环境都与特定的ECMAScript代码语法结构相关联,例如函数、代码块、TryCatch中的Catch从句,并且每次执行这类代码时都会创建新的词法环境。

词法环境有两个组成部分

环境记录

可以简单理解为相应代码块内的所有变量声明、函数声明(代码块若为函数还包括其形参)都储存于此。 ,可以当作ES3中的VO(变量对象)和AO(活动对象)

对外部词法环境的引用

用于形成多个词法环境在逻辑上的嵌套结构,以实现可以访问外部词法环境变量的能力

VariableEnvironment(变量环境)

js核心系列(二) —— 彻底理解js执行上下文

变量环境:标识其EnvironmentRecord(环境记录)保存在此执行上下文中由VariableStatements创建的绑定的词汇环境,故VariableEnvironment(变量环境)也是一个Lexical Environments(词法环境)。

在 ES6 中,词法 环境和 变量 环境的区别在于前者用于存储**函数声明和变量( let 和 const )绑定,而后者仅用于存储变量( var )绑定。

执行阶段(execution phase)

执行栈

开始之前让我们首先来了解下,执行栈的概念。执行栈,在其他编程语言中也称为“调用栈”,是一个具有先进后出 LIFO (Last in,First out)结构的堆栈,用于存储在代码执行期间创建的所有执行上下文。

js核心系列(二) —— 彻底理解js执行上下文

上面这张图,左边的乒乓球盒子就是一个很好的类比,先放进去的乒乓球,只能被最后拿出来,而最后放入的乒乓球,可以最先被拿出来。

执行阶段具体过程

当浏览器加载脚本,JS引擎从全局上下文开始执行代码,所以全局上下文被放在执行栈的最底部。

然后JS引擎再搜索代码中被调用的函数。每一次函数被调用,一个新的函数执行上下文就会被创建,并被放置在当前执行上下文的上方。

执行栈最顶部的执行栈会成为活跃执行栈,并且始终是JS引擎优先执行。

一旦活跃执行栈中的代码被执行完毕,JS引擎就会从执行栈中弹出这个执行上下文,紧接着执行下一个执行上下文,以此类推。让我们借助具体的例子来理解这一点

  var a = 10;
  
  function functionA() {
    console.log("Start function A");
    function functionB() {
      console.log("In function B");
    }

    functionB();
  }

  functionA();
  console.log("GlobalContext");

js核心系列(二) —— 彻底理解js执行上下文

一旦上述代码加载到浏览器中,JS 引擎就会将全局执行上下文推送到执行上下文栈中。当functionA从全局执行上下文中调用时,JS 引擎将functionA执行上下文压入执行上下文栈顶并开始执行functionA,当到functionB调用时,JS 引擎将functionB执行上下文压入执行上下文栈顶。当functionB执行完过后,functionB执行上下文从执行上下文栈中弹出,然后functionA执行完毕过后,functionA从执行上下文栈中弹出。当所有代码执行完毕后,JS 引擎弹出全局执行上下文,JavaScript 的执行结束。

再来一个例子:


function getName() {
    const year = getYear();
    const name = 'jimmy';
    console.log(`${name} ${year} years old this year`);
}

function getYear() {
    return 18;
}

getName(); 

js核心系列(二) —— 彻底理解js执行上下文

上面的执行上下文栈执行过程:

  1. 首先创建了全局执行上下文,当前全局执行上下文处于活跃状态。
  2. 全局代码中有2个函数 getName 和 getYear,然后调用 getName 函数,JS引擎停止执行全局执行上下文,创建了新的函数执行上下文,且把该函数上下文放入执行上下文栈顶。
  3. getName 函数里又调用了 getYear 函数,此时暂停了 getName 的执行上下文,创建了 getYear 函数的新执行上下文,且把该函数执行上下文放入执行上下文栈顶。
  4. 当 getYear 函数执行完后,其执行上下文从栈顶出栈,回到了 getName 执行上下文中继续执行。
  5. 当 getName 执行完后,其执行上下文从栈顶出栈,回到了全局执行上下文中。

参考文章

Execution context, Scope chain and JavaScript internals

Understanding Execution Context and Execution Stack in Javascript

转载自:https://juejin.cn/post/7224045063423197240
评论
请登录