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. 1. If Type(argument) is not Object, return false.

  2. 2. If argument is an Array exotic object, return true.

  3. 3. If argument is a Proxy exotic object, then

  4.    a. If argument.[[ProxyHandler]] is null, throw a TypeError exception.

  5.    b. Let target be argument.[[ProxyTarget]].

  6.    c. Return ? IsArray(target).

  7. 4. Return false.

相对于ES5来说,规范中增加了对Proxy的处理。我们再看 underscope v1.8.3 源码中对isArray的实现:

 
   
   
 
  1. _.isArray = Array.isArray || function(obj) {

  2.    return toString.call(obj) === '[object Array]';

  3. }

相对于ES5来说,规范中增加了对Proxy的处理,所以现在很多检测数组的方法,如果不支持 Proxy 的判断,可能会被淘汰哦。

语言实现细节

剩下的章节都是详细介绍语言的实现细节,正在看,占坑。

 
   
   
 
  1. # 好大一个坑

如何优雅的阅读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 2018来了,新特性都在这里

赶上 ECMAScript 潮流:用现代 JavaScript 编程

213期ECMAScript 潮流:用现代 JavaScript 编程

全面认识ECMAScript模块