执行上下文与作用域
SHEINBLOOMCHIC
执行上下文 (Execution Context Stack)也可称作函数调用栈,函数执行栈。
作用域是用来限制一个变量在程序中使用的范围。
执行上下文在运行时确定,作用域在定义时就已经确定。
作用域是用来限制一个变量在程序中使用的范围。
执行上下文在运行时确定,作用域在定义时就已经确定。
js中,函数被执行的过程分成两个部分:
- 生成执行上下文环境,确定this指向,声明变量,生成作用域链。此时函数还没有真正执行,这一步的作用是生成函数的运行环境。
- 按顺序逐行执行代码。这一步是真正的执行函数。
- 生成执行上下文(函数被调用时,函数真正执行前):
- 生成变量对象(当前函数上下文可访问的变量,变量提升发生在这个阶段)。顺序:创建arguments,创建function函数声明,创建var变量声明。
- 生成作用域链。
- 确定this指向。
- 函数执行阶段
逐行执行代码,这个阶段会完成变量赋值,函数引用,执行其他代码等。
执行上下文
js中有三种执行上下文:
- 全局执行上下文。任何不在函数内的代码都在全局上下文中。全局上下文会创建一个全局的
window/global
对象,并且设置this的值等于这个全局对象。一个程序中只会有一个全局执行上下文。 - 函数执行上下文。每个函数被调用时,都会创建一个自己的执行上下文。每个函数的执行上下文是在自身被调用的时候创建的。函数上下文可以有任意多个。
- Eval函数执行上下文。执行在
eval
函数内的代码有自己的执行上下文。但是不经常用。
执行上下文生命周期包括:创建阶段 -> 执行阶段 -> 回收阶段
创建阶段
此时函数未被真正执行。这个阶段中
- 绑定this值指向。
- 创建词法环境(LexicalEnvironment component)
- 创建变量环境(VariableEnvironment component)
ExecutionContext = { // 执行上下文(函数调用栈)
ThisBinding = <this value>, // this绑定
LexicalEnvironment = {...}, // 词法环境
VariableEnvironment = {...}, // 变量环境
}
this
值取决于当前函数被谁调用。
词法环境
词法环境指代码块内标识符与变量值、函数值之间的关联关系
- 全局环境
- 函数环境
词法环境内部有两个组件:
- 环境记录器:存储变量和函数声明的实际位置
其内包含两种类型:- 声明式环境记录器(在函数环境中):存储变量、函数和参数(arguments对象和传递给函数的参数的length)。
- 对象环境记录器(在全局环境中):用来定义出现在全局上下文中的变量和环境的关系。
GlobalExecutionContext = { // 全局执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录器:存储变量和函数声明的实际位置
Type: "Object",
// 绑定标识符
},
outer: <null> // 对外部环境的引用:可以访问其父级词法环境
}
}
FunctionExecutionContext = { // 函数执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: {
Type: "Declarative",
// 绑定标识符
},
outer: <Global or outer function environment reeference>
}
}
变量环境
变量环境也是一个词法环境,有着和上面的词法环境同样的属性。词法环境和变量环境不同之处是词法环境用来存储函数声明和let
const
绑定,变量环境用来存储 var
绑定 。
经历以上两个阶段后,通过var
定义的变量初始值为undefined
,通过let
或const
定义的变量为uninitialized
(未初始化)状态,因此不能在let
和const
变量声明前就访问。也就是我们常说的变量提升。同名的function
和var
,由于function
先被解析,因此会被同名var
覆盖。
执行阶段
变量赋值、代码执行
回收阶段
执行上下文出栈,等待虚拟机回收
作用域链
当函数在解析时,向上查找变量的过程,就是作用域链的查找过程。作用域链是执行上下文中的一部分。
评论加载中 (ง •̀ω•́)ง