一:执行上下文
执行上下文是一种对js执行代码的环境的一种
抽象
,只要js在执行中,那它一定是运行在执行上下文中
执行上下文的类型
- 全局执行上下文:全局执行上下文是在程序启动时创建的,它包含全局范围定义的变量和函数。在浏览器中,通常是在页面加载时候创建的,它是在页面整个生命周期中都存在的。
- 函数执行上下文:存在无数个函数执行上下文,但是只有函数被调用时候才会创建函数执行上下文。函数执行上下文包含函数作用域范围内的变量,函数参数,函数和作用域链。
- eval执行上下文: 指的是运行在
eval
函数中的代码,很少用而且不建议使用
示例
二:生命周期
执行上下文的生命周期为:创建阶段 —> 执行阶段 —> 销毁阶段
2.1 创建阶段
- 创建阶段:在代码执行之前,会进行对执行上下文的创建
- 全局执行上下文的创建:在整个程序启动时候,会创建全局执行上下文,其中包含全局函数,全局变量的创建、
- 函数执行上下文的创建:在函数被调用时,在函数执行前会创建函数执行上下文,其中会构建局部变量,局部函数和作用域链
具体包含三件事
- ThisBinding:this的绑定
- LexicalEnvironment(词法环境):创建词法环境
- VariableEnvironment(变量环境):创建变量环境
执行上下文对象
伪代码
//执行上下文对象
const executionContext = {
//确定this值
ThisBindings = { .....},
//创建词法环境
LexicalEnvironment = { ....},
//创建变量环境
VariableEnvironment = { ....},
}
ThisBinding
this
的值是在执行时(运行时)确定的,而不是在执行上下文创建时确定的。这意味着this
的绑定是动态的,取决于代码的实际执行情况。
词法环境
词法环境(Lexical Environment)是 JavaScript 中的一个重要概念,用于管理变量和函数的词法作用域
环境记录(Environment Record):环境记录是一个存储变量和函数声明的地方。它可以看作是一个字典或映射,将标识符(如变量名、函数名)映射到对应的值。环境记录有以下两种主要类型:
- Declarative Environment Record(声明式环境记录): 用于存储变量声明、函数声明等。这种记录可以包含诸如函数的参数、局部变量、函数声明等。
- Object Environment Record(对象环境记录): 用于与具体的对象相关联,典型的例子是与全局对象或某个特定对象的属性相关联。在这种记录中,标识符会映射到对象的属性上。
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
,声明式环境记录
- 全局执行上下文的词法环境就是
变量环境
变量环境实际上是词法环境的一个子集
- 词法环境用于收集存储函数的声明和变量(
let
和const
)的绑定 - 变量环境用于存储变量(var)的绑定
伪代码
let a = 10
const b = 100
var c = 20
function sum (number1, numebr2)
{
var res = 0
return res + number1 + number2
}
c = sum(20, 30)
执行上下文对象
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
- 由于let和const定义的a和b变量,不会出现变量提升,所以类型为
- 变量环境:收集var定义的变量的绑定,由于var定义的变量会出现变量提升,会被初始化为
undefined
函数执行上下文对象
- 词法环境:也收集函数参数
- 变量类型:res变量提升
2.2 执行阶段
- 执行阶段:在创建完成之后,会进入执行阶段
- 代码逐行进行执行,条件判断,语句赋值等都会进行执行
- 如果遇到函数调用,则会创建函数执行上下文,并且将该函数的执行上下文压入到
执行栈
中
2.3 回收阶段
- 当代码块执行完毕或函数执行完毕时,执行上下文进入执行结束和销毁阶段。
- 在这个阶段,局部变量通常会被销毁,内存资源得到释放。
三:执行栈
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');
执行上下文的创建和销毁是一个动态的过程,由 JavaScript 引擎负责管理。执行上下文的栈结构(调用栈)用于跟踪代码的执行顺序,并确保上下文按照正确的顺序进入和离开。这种生命周期管理有助于确保变量的作用域、函数的调用顺序和内存资源的释放都得以正确执行。