读懂 ECMA 规格
一般我们都不关心 ECMA 规范,只需要学习怎么使用就好了。但有时候遇到一些难以解释的问题/现象,就不得不看一下规范是如何要求实现的了。规范内容庞杂,理解其中的术语有利于我们快速看懂规范。
Environment
环境指定了标识符在表达式中的意义。譬如当谈论表达式 x + 1 时,如果不指明 x 所在的环境,那么这个表达式就毫无意义。为我们熟知的环境有:全局环境,函数的局部环境。
注意,环境类似作用域(Scope),不过作用域是 ES5 之前的概念。
Lexical Environments
词法环境是一个规范类型,用于定义特定变量和函数标识符在 ECMAScript 代码的词法嵌套结构上的关联关系。一个词法环境由一个环境记录项和可能为空的外部词法环境引用构成。
Execution Contexts
执行上下文是一个抽象的规范概念,解释器用它来追踪 ECMAScript 代码的运行时求值。在代码执行过程中,可能会出现多个执行上下文,但运行的执行上下文最多只有一个。为了管理执行上下文,我们引入了执行上下文栈,处于栈顶的那个元素就是运行的执行上下文。
当解释器遇到函数、块语句、Catch从句时,都会创建一个新的执行上下文后压入执行上下文栈,成为运行时执行上下文。
主要介绍执行上下文包含的如下属性:
- VariableEnvironment 持有在这个执行上下文内, var 声明标识符绑定。
- LexicalEnvironment 保存在这个执行上下文内,不属于 VariableEnvironment 的其他标识符绑定。
LexicalEnvironment 和 VariableEnvironment 都是词法环境。
函数声明比较特别,它可以存在于上面两种环境中的任一种,这取决于函数所在的环境。在 Module 环境下,函数声明作为词法声明保存在 LexicalEnvironment。在其他情况下保存在 VariableEnvironment 内。
Record 和 field
ES6 规格将键值对(key-value map)的数据结构称为 Record,其中的每一组键值对称为 field。这就是说,一个 Record 由多个 field 组成,而每个 field 都包含一个键名(key)和一个键值(value)。
为了方便理解,我们可以将一个 Record 看做一个对象({})。
identifier binding
标识符绑定,将一个标识符和对应的值(数字、函数、对象等)绑定在一起。一个标识符不仅可以被绑定,也可以被解除绑定。如果一个标识符与一个对象绑定在一起,它便引用了这个对象,通过这个标识符就可以去访问和修改那个对象。
白话版:将值赋值给标识符
在 javascript 中,标识符绑定是按值传递的。
identifier resolver
标识符解析,指在运行的执行上下文中的词法环境里,通过标识符获得其对应绑定的过程。这一过程和原型链查找类似。
白话版:获取标识符的值
closure
闭包是一个组合,由代码块和代码块创建时所在的词法环境组成,是一个可以自己拥有独立的环境与变量的的表达式(通常是函数)。
在 es6 中,所有函数都是闭包。why?
evaluate
计算、求值、运行,根据上下文而定