ECMAScript 2018 标准导读
Posted SegmentFault
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ECMAScript 2018 标准导读相关的知识,希望对你有一定的参考价值。
前言
本文是对《ECMAScript 2018 Language Specification》(https://tc39.github.io/ecma262)的解读。 本文是对标准的概述性解读,不会针对某个技术点进行详细展开,但是会附上相关文章外链。
规格介绍
整个文档有引言+27个章节+7篇附录,大概五六百页的样子。
引言和前面3章部分,都是在讲规格本身,跟JS语言本身无关。内容很少,可以快速过一遍。
Introduction 部分 介绍了语言历史和标准化历程;
前3章 Scope、Conformance、Normative References 主要介绍了文档的范围、一致性和参考文献。所谓一致性,实际上是标准实现的一致性,任何实现ECMAScript 标准的语言,都必须完全实现文档中描述的语法和语义,并且可以有规格之外的自定义程序语法。
语言概述
第4章 Overview 是对语言的整体介绍。涵盖了Web脚本语言环境、ES基本概念和专业术语,以及严格模式的简单介绍。这里跟大家分享几个有意思的点。
奇葩的面向对象机制
ECMAScript is an object-oriented programming language for performing computations and manipulating computational objects within a host environment. ES是一门面向对象的语言,这是官方描述!(
这有什么奇怪的啊,大家都知道啊
)但是ES的面向对象设计机制却是与众不同,大有学问(这有什么啊,不就原型链嘛
)。我们多少都了解一些,但要完全讲清楚,恐怕专门开一篇博客也不够。
但我还是尝试专门写了一篇:《如何优雅的解读JS的面向对象机制》。
脚本语言的逆袭
ECMAScript was originally designed to be used as a scripting language, but has become widely used as a general-purpose programming language.
这个就有点屌了,ES最初是被拿来当Web脚本语言用的,但现在已经成了时下最流行的通用编程语言之一。此中缘由大家应该也很清楚,不多说,只是抒发一下感慨: Alwaysbet on JS
可不是乱说的。
有关对象的描述
本章还列举出了JS中的专业名词及解释,比如类型、原始值、对象、构造器、原型......等概念。有意思的是标准中关于对象的描述在ES5里面有三种:
native object(原生对象),指语义完全由规范定义并且不掺杂任何宿主环境定义的的对象;
build-in object(内置对象),由ECMA实现提供,程序执行时就存在的对象。所有内置对象都是原生对象。
host object(宿主对象),由执行环境提供,比如浏览器的window对象和history对象。JS里的对象不是原生对象就是宿主对象。
但是在ES6之后就改成了四种:
ordinary object:普通对象,只要具备了对象的所有基本内置方法就可以了。
exotic object:外来对象,如果不具备标准对象所有的基本内置方法,就是外来对象。JS里的对象不是普通对象就是外来对象。
standard object:标准对象,语义由本规范定义的对象。
built-in object:内置对象,跟ES5中描述一样。
对比来看,前者是以宿主环境为划分条件,后者则是以对象的基本内置方法。ES6之后其实划分的更细了。
记法约定
第5章 Notational Conventions 详细介绍了规范描述中用到的一些句法、词法以及算法约定等内容,如果要看懂后面的有关语法行为,函数实现的详细描述,就得看懂这章,看完之后你甚至可以照着标准实现一遍。
这章涉及大量编译基本知识,还是强烈建议花些时间看下,不然后面可能没法继续。你需要知道以下概念:
上下文无关文法
作为ECMAScript规格文档,自然需要用一种专业的方式来描述这门语言,这种专业的描述语言的方法,就是所谓的文法(文法由若干产生式组成)。而上下文无关的意思,就是所有产生式的左边只有一个非终结符,因为只有这样,产生式右边的串才能规约到左边的非终结符,否则就是上下文相关。大部分编程语言都是上下文无关文法,ECMAScript也不例外。
词法、正则文法、数字字符串文法和句法约定
一个冒号“:”作为分隔符分割句法的产生式。两个冒号“::”作为分隔符分割词法和正则的文法产生式。词法和正则的文法共享某些产生式。三个冒号“:::”作为分隔符分割数字字符串文法的产生式。然后列举了各种句法,文法标记,总之很多概念,此处不展开。
内部机制
第6到8章详细描述了语言运行的内部机制,从宏观上对ES进行描述,包括数据类型和值,语言内部的抽象操作,以及代码执行的上下文相关知识。
类型
ES中的类型可细分为ES语言类型和规范类型,语言类型对应的是程序中直接被操作的值的类型,包括Undefined,Null,Boolean,Number,String,Object,Symbol。理解类型,是理解这门语言的基础。
首先是Undefind和Null,二者区别可参考 undefined与null的区别 - 阮一峰。在一门编程语言中对于“空”的描述用到了两种基本类型,估计只有javascript了。其实一开始只有null,后来为了解决类型转换和错误处理问题引入了undefined。
undefined 表示此处应该有个值,但是这个值还没给出来,其实就是占了个坑,这个坑是语言内部实现帮你做的,你不用管。null 才是真正意义上的空值,表示对象世界中的“无”。正所谓道生一,一生二,二生三,三生万物。JS中万物皆对象,所有对象的原型链都可以上溯到唯一的Object,而Object的原型,正是万物之始源,混沌之道null。所以JS中null的意义远超其他编程语言,这正是让JS的面向对象思想与道家哲学完美契合的重要一笔。
所以个人理解,Undefined虽然作为基本类型,解决的却是语言内部处理问题,所以永远不要在代码中主动出现,要在语义上处理空就用null。所有因为undefined带来的问题,基本上是占着茅坑不拉屎的行为导致。所以google在Dart中就只有null,而没有undefined,因为undefined解决的问题完全可以在语言内部解决,没必要暴露给用户。
Boolean和Symbol没啥好说的,数值的设计也是从简,只有一个Number类型。有意思的是String,官方对于String类型的描述:
The String type is the set of all ordered sequences of zero or more 16-bit unsigned integer values (“elements”) up to a maximum length of 2e53 - 1 elements. 翻译过来就是指所有有限的零个或多个16位无符号整数值的有序序列(共计2e53 - 1个元素)。这个2e53 - 1是怎么来的呢,按照16位无符号整数值计算的话?
更有意思的是,String中的每一个字符都被视为独立的UTF-16代码单元,即占2个字节,作用在字符串上的所有操作都视它们为无差别的16位无符号整数(这里的UTF-16,其实是指内部实现,计算机内存中都是基于unicode编码的,只是在存储或读取时会进行UTF-8或者其他编码类型转换)。但是UTF-16却有两种长度的字符,U+0000到U+FFFF之间的字符占2个字节,U+10000到U+10FFFF之间的字符占4字节。对于4字节的字符ES是无法准确处理的,需要自己去根据编码值情况判断,这也是一大坑爹之处。
对此,我也专门写了一篇:《深入理解JavaScript中的String类型-未发布》。
除了以上语言类型,整个规范中还有用于描述这门语言的规范类型,规范类型的值是规范自己造的,有的还是ES表达式计算的中间结果,所以没必要对应到特定的语言类型上。若非特别说明,ES中的类型通常指语言类型。
操作摘要
类型之间会涉及到各种运算,这就会涉及到各种操作运算。比如类型转换涉及到的内部机制和算法流程,7.1 Type Conversion 都有详细说明。7.2 Testing and Comparison Operations 讲了测试和比较操作,比如测试一个对象是否是数组,是否数字,是否构造函数,以及 ==
和 ===
的定义等等。以数组测试操作isArray(argument)为例,标准中的描述如下:
1. If Type(argument) is not Object, return false.
2. If argument is an Array exotic object, return true.
3. If argument is a Proxy exotic object, then
a. If argument.[[ProxyHandler]] is null, throw a TypeError exception.
b. Let target be argument.[[ProxyTarget]].
c. Return ? IsArray(target).
4. Return false.
相对于ES5来说,规范中增加了对Proxy的处理。我们再看 underscope v1.8.3 源码中对isArray的实现:
_.isArray = Array.isArray || function(obj) {
return toString.call(obj) === '[object Array]';
}
相对于ES5来说,规范中增加了对Proxy的处理,所以现在很多检测数组的方法,如果不支持 Proxy 的判断,可能会被淘汰哦。
语言实现细节
剩下的章节都是详细介绍语言的实现细节,正在看,占坑。
# 好大一个坑
如何优雅的阅读ECMA标准
由于目前使用最为广泛的还是ECMA 5.1版本,所以在阅读ES2018之前,建议先把5.1的标准看一遍,方便对比。好在W3C中文站有5.1的100%翻译版本:
ES5中文版: https://www.w3.org/html/ig/zh/wiki/ES5
然后可以再看ES6也就是ES2015的标准,虽然没有中文版,不过可以参考阮老师的ES6入门,顺便也可以瞄一眼ES2016的标准:
ES 2015: http://www.ecma-international.org/ecma-262/6.0/ ECMAScript 6入门教程: http://es6.ruanyifeng.com/ ES 2016: http://www.ecma-international.org/ecma-262/7.0/
期间有任何疑惑可以参考MDN上的JS参考文档,非常全面,涵盖了从入门到精通。
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference
看完这些再看ES2018就会非常轻松了:
https://tc39.github.io/ecma262/
插播一则官方消息
SegmentFault 官方成立了「SF.GG 广州技术交流群」。
群成员:广州地区的程序员,不限技术领域。
群定位:大家可自由在群内讨论、分享技术内容及同城职位推荐,管理猿也会定期分享技术内容。当然,这里也是你结交同城程序猿/媛的地方,成员可自由组织线下约饭、交流。
扫码添加管理员的微信,添加请备注:SF用户名+广州技术交流群,管理员会邀请你入群 lol
以上是关于ECMAScript 2018 标准导读的主要内容,如果未能解决你的问题,请参考以下文章
译ECMAScript 2016, 2017, 2018 新特性之必读篇
应用广泛的语言ECMAScript 2018来了,新特性都在这里
赶上 ECMAScript 潮流:用现代 JavaScript 编程