前言在谈一个概念之前,我们需要先确定它的前提。本文基于ECMAScript5,写了一句话解释,执行上下文就是一段代码执行的所有信息。执行什么是上下文?《重学前端》的作者Winter曾经解释过什么是执行上下文:JavaScript标准将一段代码(包括函数)执行所需的所有信息定义为:“执行上下文,他整理了不同ECMAScript中的执行上下文执行上下文在版本中的含义:执行上下文在ES3中包含三部分。scope:作用域,也常被称为作用域链variableobject:变量对象,用来存储变量的对象thisvalue:thisvalue在ES5中,我们改进了命名方式,将执行上下文的前三部分改成如下样子thislexicalenvironment:词法环境,获取变量时使用variableenvironment:variableenvironment,声明变量时使用thisvalue:thisvalue在ES2018中,执行上下文又变成这样了,thisvalue归类到lexicalenvironment,但是内容很多已添加。lexicalenvironment:词法环境,获取变量或this值时使用变量环境variableenvironment:变量环境,声明变量时使用codeevaluationstate:用于还原代码执行位置Function:当执行的任务是函数时使用,表示函数beingexecutedScriptOrModule:当被执行的任务是脚本或模块时使用,表示正在执行的代码根据选新不选旧的原则,本文应该从ES2022开始,最后是ES2018,但是主流解释和执行上下文都以ES3/ES5为例。经过权衡,笔者将以ES5为基础编写执行上下文,后续在ES3中加入执行上下文执行生命周期。我们在讲词法环境的时候,曾经画过一个执行生命周期图。提到的执行上下文是指如果在引擎执行阶段要执行一段代码,会先将全局执行上下文压入调用栈(callstack);然后创造一个词法环境。这时要提升变量,提升函数,并将这些变量注册到词法环境中(编译阶段);然后进入执行阶段,执行可执行代码,赋值,遇到函数时,创建函数执行上下文,将函数的执行上下文压入调用栈;然后创建函数的词法环境,当函数执行完毕,将从调用栈中弹出;如此循环,直到调用栈中只剩下一个全局执行上下文,除非关闭浏览器,否则全局执行上下文不会弹出我们要将执行上下文压入调用栈,调用的数据结构堆栈是一个堆栈。如果我们的代码像这样,功能是先进后出的vara=1;functionfoo(){functionbar(){console.log(a);}bar();}functionbaz(){foo();}baz();那么执行过程应该是这样的:图中蓝色方块就是执行上下文,外面黑框白底的区域就是模拟的调用栈。整个过程遵循先进后出的原则。任何代码执行前,先创建全局执行上下文,压入调用栈(编译阶段)创建词法环境,注册函数声明和变量声明(编译阶段),引擎执行到baz(),创建baz()的函数执行上下文,并将其压入调用堆栈。函数baz()调用foo(),创建foo()的执行上下文,并将其压入调用堆栈。),创建bar()执行上下文,并将其压入调用堆栈。函数bar()执行console.log(),并以相同的方式将其压入调用堆栈。执行console.log()后,弹出函数bar(),同时执行弹出调用栈函数foo(),同时执行弹出调用栈函数baz(),pop-upcallstack只剩下globalexecutioncontext,这里保留在栈底,我们看到console.log()也被压入了执行栈,不禁想到,会是哪些代码元素执行到调用栈?可执行代码其实不仅仅是function可以作为执行上下文在执行栈中运行,JavaScript中定义了四种可执行代码:globalcode:整个js文件functioncode:functioncodemodule:模块代码evalcode:put在eval的代码中,你会看到console.log()被压入了调用栈,因为它属于全局代码执行步骤。JavaScript引擎根据可执行代码执行代码。每次执行的步骤如下:CreateanewExecutionContext创建一个新的词法环境(LexicalEnvironment),将LexicalEnvironment和VariableEnvironment指向新创建的词法环境,将这个执行上下文压入执行栈,成为正在运行的执行上下文。上下文弹出执行栈如何创建执行上下文?现在我们知道JavaScript如何管理执行上下文,现在让我们了解JavaScript引擎如何创建执行上下文。创建执行上下文有两个阶段:1)创建阶段和2)执行阶段创建阶段在JavaScript代码执行之前,执行上下文会经历创建阶段。在创建阶段会发生以下三件事:this值的确定,称为this绑定。创建一个LexicalEnvironment组件,并创建一个VariableEnvironment组件,因此执行上下文在概念上表示如下:ExecutionContext={ThisBinding=
