首先, 介绍几个规范定义的概念:
-
Identifier
标识, 如let a
,a
就是标识, 保留字段不能做为标识 -
ECMAScript Language Types
Undefined
,Null
,Boolean
,String
,Symbol
,Number
,BigInt
,Object
-
ECMAScript Language value
ECMAScript Language Types 的特征值
Environment Record(环境记录)
Environment Records用来描述Identifier和具体的变量或函数之间的关系, 这种关系的确定基于词法分析
每一个 Environment Record 都有 [[OuterEnv]]
字段指向 null
或其它 Environment Record, 通过这种形式实现链式查询
Environment Record 有如下分层:
- Environment Record
- declarative Environment Record
包含 variable(var
), constant(const
), let, class, module, import, function declarations- function Environment Record
函数的顶级作用域, 非箭头函数, 提供this
绑定. 非箭头函数且引用super
, 提供super
调用所必需的支持 - module Environment Record
模块的外层作用域
- function Environment Record
- object Environment Record
提供一个绑定对象, Identifier 对应于绑定对象的属性名, 参考 with - global Environment Record
最外层的共享作用域, 通过 realm 提供
- declarative Environment Record
PrivateEnvironment Records(私有环境记录)
PrivateEnvironment Record 用于追踪 Class
私有属性
Realms(领域)
在执行之前,所有 ECMAScript 代码都与一个 realm 相关联
realm 包含以下字段:
- [[Intrinsics]]
内在对象 - [[GlobalObject]]
全局对象 - [[GlobalEnv]]
global Environment Record - [[TemplateMap]]
用于 Tagged templates - [[HostDefined]]
任何值, 默认为undefined
, 用于记录 Host 的额外信息
Execution Contexts(执行上下文)
执行上下文的组成:
组成 | 作用 |
---|---|
code evaluation state | 表明当前上下文的代码状态(执行, 暂停, 恢复) |
Function | 如果当前上下文作用于 function object, 则该值为 function object, 否则为 null |
Realm | 参考上文 |
ScriptOrModule | 当前代码的 Module Record 或 Script Record, 如果代码没有初始的 script 或 module, 则该值为 null |
LexicalEnvironment | Environment Record, 用于解析 Identifier |
VariableEnvironment | Environment Record, 仅记录了 VariableStatement(var 声明) 绑定的 Identifier |
PrivateEnvironment | PrivateEnvironment Records, 不包含 Class, 则该值为 null |
LexicalEnvironment 和 VariableEnvironment 组成了执行上下文的 Environment Record
区分 LexicalEnvironment 和 VariableEnvironment 是因为在执行代码时, VariableEnvironment 是不会变化的, 而 LexicalEnvironment 在遇到某些语法, 如块结构( { ... }
), 需要创建新的 LexicalEnvironment, 一般情况下, 新的 LexicalEnvironment 的 [[OuterEnv]]
字段指向旧的 LexicalEnvironment
running execution context (运行中的执行上下文)是当前正在运行的代码关联的执行上下文
通常函数执行前, 会创建相应的执行上下文
浏览器实现情况
所谓变量提升, 即 var
声明 存在于 VariableEnvironment:
console.log(a); // undefined
if(false) {
var a = 0;
}
但是关于函数声明似乎与规范不一致, 规范表明 VariableStatement
如下:
所以 函数声明 不属于 VariableStatement
,即 函数声明不存在于 VariableEnvironment, 但目前 Chrome 下代码表现不是如此, 也存在变量提升情况:
console.log(a); // undefined
if(false) {
function a() {}
}