[译]如何阅读ECMAScript规范
翻译本文的目的是尝试给出ECMAScript规范中核心术语的译法,供同好品评。
原文链接:https://timothygu.me/es-howto/
摘要
ECMAScript语言规范(又称JavaScript规范或ECMA-262)是学习JavaScript复杂工作原理的一手资料。然而,其浩繁的卷帙一开始总会让人无从下手、望而生畏。本文旨在降低阅读这一最佳JavaScript语言参考的阅读门槛。
目录
1. 前言
1.1 为什么应该阅读ECMAScript规范
1.2 什么属于ECMAScript规范,什么不属于
1.3 先别急,ECMAScript规范在哪里?
1.4 查阅规范2. 运行时语义
2.1 算法步骤
2.2 抽象操作
2.3 什么是[This]
2.3.1 Record的字段
2.3.2 JavaScript对象的内部栏位
2.3.3 JavaScript对象的内部方法
2.4 完成记录:?
与!
2.5 JavaScript对象
2.6 示例:String.prototype.substring()
2.7 示例:Boolean()
和String()
可以抛异常吗?
2.8 示例:typeof
操作符术语表
常见抽象操作参考
参考资料
1. 前言
你肯定知道,每天读一点ECMAScript规范有益健康。无论它是你新年的小目标,还是仅仅为了遵照医嘱,反正欢迎阅读本文!
注意:本文只在指称规范是使用“ECMAScript”,其他地方使用“JavaScript”。不过,这两个词指的是同一个东西。(历史上,ECMAScript和JavaScript有一些区别,不过那不是本文的重点,大家可以自行搜索。)
1.1 为什么应该阅读ECMAScript规范
ECMAScript规范是实现JavaScript的权威资料,不管是在浏览器中,在Node.js中,还是在IoT设备中。所有JavaScript引擎的开发者都依靠这份文档确保自己的新特性能够跟其他JavaScript引擎一样如期工作。
不过必须得说明一下,规范的效用绝对不仅仅限于被称为“JavaScript引擎开发者”的那些神秘人物。实际上,规范对你我这样的普通JavaScript程序员一样有用,只是你还不知道罢了。
假如有一天你发现了下面这个问题:
> Array.prototype.push(42)
1
> Array.prototype
[ 42 ]
> Array.isArray(Array.prototype)
true
> Set.prototype.add(42)
TypeError: Method Set.prototype.add called on incompatible receiver #<Set>
at Set.add (<anonymous>)
> Set.prototype
Set {}
并且想不通为什么一个方法可以对自己的原型起作用,而另一个方法却不能对自己的原型起作用。可惜谷歌总是在你最需要帮助时失灵,而一直给力的Stack Overflow居然也无能为力。
看规范可以找到答案。
或者,你可能就是想知道臭大街的松散相等操作符(==
)到底怎么起作用。作为曾经勤奋好学的软件工程师,你在MDN上查到几段解释,但看来看去只会越来越晕。
看规范可以找到答案。
话说回来,我也不推荐JavaScript新手看ECMAScript规范。如果你才开始接触JavaScript,那还是先写几个网页或者Web应用吧!要不就写个基于JavaScript的保姆摄像头!别的什么东西也行!等你体会到足够多的JavaScript缺点,或者已经足够有钱而不必再担心JavaScript了,再回来看这篇文章不迟。
好啦,现在大家知道规范对于理解语言或平台的工作机制非常有帮助了。但要阅读ECMAScript规范,到底应该从哪里入手呢?
1.2 什么属于ECMAScript规范,什么不属于
1.3 先别急,ECMAScript规范在哪里?
谷歌“ECMAScript规范”,会看到很多结果,都说是合法规范。那应该看哪一个?
长话短说,tc39.es/ecma262/这个规范最可能是你想看的。
ECMAScript语言规范由具有不同背景的一群人共同制定,这群人就是TC39(即Ecma International Technical Committee 39)。TC39在tc39.es上面维护着ECMAScript语言的最新规范。
问题在于,TC39每年都会在某个时间点将规范的一个快照变成该年度的ECMAScript Language标准,并给它分配一个版本号。比如,ECMAScript® 2019 Language Specification (ECMA-262, 10th edition)(常被称为ES10或ES2019)就是2019年6月份在tc39.es上看到的规范,把它放福尔马林里那么一泡,一塑封并给出个PDF版,就永久封存了。
为此,除非你只想让自己的Web应用在2019年6月份之前发布的浏览器上跑,否则就应该只看tc39.es上最新的规范。但如果你想(或必须)支持旧版本浏览器或Node.js,那可能老版本规范有用。
ISO/IEC也把ECMAScript语言标准重新发布为ISO/IEC 22275。不过别担心,因为该标准基本上就是一个指向ECMAScript规范的超链接。
1.4 查阅规范
ECMAScript规范涉及的内容极多。即使规范的作者全力将它分成有逻辑的部分,仍然可以用卷帙浩繁来形容。
从个人角度,我喜欢将规范分成五部分。
- 约定与基础(“什么是Nubmer?规范中说「抛出TypeError异常」时意味着什么?”)
- 语言的文法产生式(“程序员应该怎么写
for
-in
循环?”) - 语言的静态语义(“怎么确定
var
语句中的变量名?”) - 语言的运行时语义(
如何执行
for-
in循环?
) - API(“
String.prototype.substring()
能做什么?”)
不过规范并不是这么组织的。事实上,它把第一个项目符号放在了“§5 表示方式约定”到“§9 普通与异质对象行”中,接下来三个项目符号穿插放在了“§10 ECMAScript语言:源代码”到“§15 ECMAScript语言:脚本与模块”中,比如:
§13.6 if语句文法产生式
- §13.6.1-6 静态语义
- §13.6.7 运行时语义
§13.7 迭代语句文法产生式
- §13.7.1 共享的静态和运行时语义
§13.7.2
do
-while
语句
- §13.7.2.1-5 静态语句
- §13.7.2.6 运行时语义
- §13.7.3
while
语句- ……
而AP则分布在条款“§13 全局对象”到“§27 反射”中。
现在,我想说明一下,绝对没有人从头到尾地读规范。而是只会看与自己想寻找的答案相关的部分,而在该部分中则只看那些需要的地方。因此要学会判断你的问题与上述五大部分中的哪些相关。如果想不出来,可以问自己一个问题:“这个(你想确认的东西)是什么时间被求值的?”,应该有帮助。别担心,查规范查得越多就会越容易的。
2. 运行时语义
语言和API的运行时语义是规范中最大一部分,通常也是人们问题最多的地方。
总体来看,规范中这些部分都很直观明了。不过,规范使用的很多简写形式,让刚开始阅读的人(至少让我)感到很讨厌。接下来会解释一些这种约定,然后通过分析几个特性的原理来看看怎么使用它们。
2.1 算法步骤
ECMAScript中的大多数运行时语义都是通过一系列算法步骤规定的,不像伪代码,但更精确。
示例1
算法步骤的示例:
- 令
a
为1;- 令
b
为a+a
;若
b
为2,则
- 哇!没算错。
否则
- 去!
继续阅读:“§5.2 算法约定”
2.2 抽象操作
有时候,你会看到一个类似函数调用的东西。Boolean()
函数的第一步是: