抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

一:执行上下文

执行上下文是一种对js执行代码的环境的一种抽象,只要js在执行中,那它一定是运行在执行上下文中

执行上下文的类型

  • 全局执行上下文:全局执行上下文是在程序启动时创建的,它包含全局范围定义的变量和函数。在浏览器中,通常是在页面加载时候创建的,它是在页面整个生命周期中都存在的。
  • 函数执行上下文:存在无数个函数执行上下文,但是只有函数被调用时候才会创建函数执行上下文。函数执行上下文包含函数作用域范围内的变量,函数参数,函数和作用域链。
  • eval执行上下文: 指的是运行在 eval 函数中的代码,很少用而且不建议使用

示例

image-20230907172008540

二:生命周期

执行上下文的生命周期为:创建阶段 —> 执行阶段 —> 销毁阶段

2.1 创建阶段

  • 创建阶段:在代码执行之前,会进行对执行上下文的创建
    • 全局执行上下文的创建:在整个程序启动时候,会创建全局执行上下文,其中包含全局函数,全局变量的创建、
    • 函数执行上下文的创建:在函数被调用时,在函数执行前会创建函数执行上下文,其中会构建局部变量,局部函数和作用域链

具体包含三件事

  • ThisBinding:this的绑定
  • LexicalEnvironment(词法环境):创建词法环境
  • VariableEnvironment(变量环境):创建变量环境

执行上下文对象

伪代码

1
2
3
4
5
6
7
8
9
//执行上下文对象
const executionContext = {
//确定this值
ThisBindings = { .....},
//创建词法环境
LexicalEnvironment = { ....},
//创建变量环境
VariableEnvironment = { ....},
}

ThisBinding

this 的值是在执行时(运行时)确定的,而不是在执行上下文创建时确定的。这意味着 this 的绑定是动态的,取决于代码的实际执行情况。

词法环境

词法环境(Lexical Environment)是 JavaScript 中的一个重要概念,用于管理变量和函数的词法作用域

环境记录(Environment Record):环境记录是一个存储变量和函数声明的地方。它可以看作是一个字典或映射,将标识符(如变量名、函数名)映射到对应的值。环境记录有以下两种主要类型:

  • Declarative Environment Record(声明式环境记录): 用于存储变量声明、函数声明等。这种记录可以包含诸如函数的参数、局部变量、函数声明等。
  • Object Environment Record(对象环境记录): 用于与具体的对象相关联,典型的例子是与全局对象或某个特定对象的属性相关联。在这种记录中,标识符会映射到对象的属性上。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GlobalExectionContext = {  // 全局执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录
Type: "Object", // 全局环境
// 标识符绑定在这里
outer: <null> // 对外部环境的引用
}
}

FunctionExectionContext = { // 函数执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录
Type: "Declarative", // 函数环境
// 标识符绑定在这里 // 对外部环境的引用
outer: <Global or outer function environment reference>
}
}
  • 在创建执行上下文的时候,会对不同的执行上下文对象的词法环境类型进行记录
    • 全局执行上下文的词法环境就是Object Environment Record,对象环境记录
    • 函数执行上下文的词法环境就是Declarative Environment Record,声明式环境记录

变量环境

变量环境实际上是词法环境的一个子集

  • 词法环境用于收集存储函数的声明和变量(letconst)的绑定
  • 变量环境用于存储变量(var)的绑定

伪代码

1
2
3
4
5
6
7
8
9
10
   let a = 10
const b = 100
var c = 20

function sum (number1, numebr2)
{
var res = 0
return res + number1 + number2
}
c = sum(20, 30)

执行上下文对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
GlobalExectionContext = {

ThisBinding: <Global Object>,

LexicalEnvironment: { // 词法环境
EnvironmentRecord: {
Type: "Object",
// 标识符绑定在这里
a: < uninitialized >,
b: < uninitialized >,
sum: < 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",
// 标识符绑定在这里
res: undefined
},
outer: <GlobalLexicalEnvironment>
}
}

全局执行上下文对象

  • 词法环境:收集变量let和const的绑定和函数提升
    • 由于let和const定义的a和b变量,不会出现变量提升,所以类型为uninitialized(未初始化状态)
    • sum出现函数提升
    • outer:由于是全局执行上下文,不会再有外部环境的引用,所以类型为Null
  • 变量环境:收集var定义的变量的绑定,由于var定义的变量会出现变量提升,会被初始化为undefined

函数执行上下文对象

  • 词法环境:也收集函数参数
  • 变量类型:res变量提升

2.2 执行阶段

  • 执行阶段:在创建完成之后,会进入执行阶段
    • 代码逐行进行执行,条件判断,语句赋值等都会进行执行
    • 如果遇到函数调用,则会创建函数执行上下文,并且将该函数的执行上下文压入到执行栈

2.3 回收阶段

  • 当代码块执行完毕或函数执行完毕时,执行上下文进入执行结束和销毁阶段。
  • 在这个阶段,局部变量通常会被销毁,内存资源得到释放。

三:执行栈

1
2
3
4
5
6
7
8
9
10
11
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');

img

执行上下文的创建和销毁是一个动态的过程,由 JavaScript 引擎负责管理。执行上下文的栈结构(调用栈)用于跟踪代码的执行顺序,并确保上下文按照正确的顺序进入和离开。这种生命周期管理有助于确保变量的作用域、函数的调用顺序和内存资源的释放都得以正确执行。

评论