4 概述
本节包含 ECMAScript 语言的非规范性概述。
ECMAScript 是一种面向对象的编程语言,用于在宿主环境 中执行计算并操作计算对象。此处定义的 ECMAScript 并不打算在计算上自给自足;实际上,本规范并未规定外部数据输入或计算结果输出。相反,预期 ECMAScript 程序的计算环境不仅会提供本规范所描述的对象和其他设施,还会提供某些特定于环境的对象,而这些对象的描述和行为超出了本规范的范围;本规范仅指出它们可能提供某些可从 ECMAScript 程序访问的属性和可调用的函数对象 。
ECMAScript 最初被设计为一种脚本语言,但现已广泛用作通用编程语言。脚本语言 是一种用于操纵、定制和自动化现有系统功能的编程语言。在这类系统中,有用的功能已经通过用户界面可用,而脚本语言则是一种将这些功能暴露给程序控制的机制。以这种方式,现有系统被称为提供了对象和设施的宿主环境 ,它补全了脚本语言的能力。脚本语言既面向专业程序员,也面向非专业程序员。
ECMAScript 最初被设计为一种Web 脚本语言 ,用于为浏览器中的网页注入活力,并作为基于 Web 的客户端-服务器架构的一部分执行服务器端计算。现在,ECMAScript 已被用于为各种宿主环境 提供核心脚本能力。因此,核心语言在本文档中独立于任何特定宿主环境 进行规定。
ECMAScript 的使用已经超越了简单脚本,如今它被用于许多不同环境和不同规模下的完整编程任务范围。随着 ECMAScript 使用范围的扩大,它所提供的特性和设施也随之扩展。ECMAScript 现在已经是一种功能完备的通用编程语言。
4.1 Web 脚本
Web 浏览器为客户端计算提供 ECMAScript 宿主环境 ,其中包括例如表示窗口、菜单、弹出窗口、对话框、文本区域、锚点、框架、历史记录、cookie 和输入/输出的对象。此外,宿主环境 还提供了将脚本代码附加到诸如焦点变化、页面和图像加载、卸载、错误与中止、选择、表单提交以及鼠标操作等事件的方法。脚本代码出现在 HTML 中,而显示出的页面则是用户界面元素、固定文本和计算所得文本与图像的组合。脚本代码会响应用户交互,因此不需要主程序。
Web 服务器则为服务器端计算提供了另一种宿主环境 ,其中包括表示请求、客户端和文件的对象,以及用于锁定和共享数据的机制。通过结合浏览器端和服务器端脚本,可以在客户端与服务器之间分配计算任务,同时为基于 Web 的应用提供定制化用户界面。
每个支持 ECMAScript 的 Web 浏览器和服务器都提供其自己的宿主环境 ,从而补全 ECMAScript 的执行环境。
4.2 宿主与实现
为帮助将 ECMAScript 集成到宿主环境 中,本规范将某些设施(例如抽象操作 )的定义全部或部分延后到本规范之外的来源。就编辑表达而言,本规范区分以下几类延后定义。
实现 是一个外部来源,它进一步定义了附录 D 中列举的设施,或者那些被标记为实现定义 (implementation-defined)或实现近似定义 (implementation-approximated)的设施。在非正式用法中,实现指的是具体制品,例如某个特定的 Web 浏览器。
实现定义 设施,是指其定义被无进一步限定地延后到外部来源的设施。本规范不对具体行为提出任何建议,符合规范的实现可以在本规范施加的约束内自由选择任意行为。
实现近似定义 设施,是指其定义被延后到外部来源,但同时推荐一种理想行为。尽管符合规范的实现可以在本规范施加的约束内自由选择任意行为,但仍鼓励其尽量逼近该理想行为。某些数学运算,例如 Math.exp ,属于实现近似定义 。
宿主 是一个外部来源,它进一步定义了附录 D 中列出的设施,但不会进一步定义其他实现定义 或实现近似定义 的设施。在非正式用法中,宿主 指的是一组以相同方式通过附录 D 与本规范接口的所有实现,例如所有 Web 浏览器的集合。宿主 通常是外部规范,例如 WHATWG HTML(https://html.spec.whatwg.org/ )。换言之,宿主定义 的设施通常会在外部规范中得到进一步定义。
宿主钩子 是一个抽象操作 ,其定义全部或部分由外部来源给出。所有宿主钩子 都必须列在附录 D 中。宿主钩子 至少必须符合以下要求:
宿主定义 设施,是指其定义被无进一步限定地延后到外部来源,且列在附录 D 中。不是宿主 的实现也可以为宿主定义 设施提供定义。
宿主环境 是对所有宿主定义 设施的一组特定定义选择。宿主环境 通常包括一些对象或函数,它们允许作为全局对象 的宿主定义 属性来获取输入和提供输出。
本规范遵循一种编辑约定,即始终使用最具体的术语。例如,如果某项设施是宿主定义 的,则不应称其为实现定义 。
宿主 和实现都可以通过本文中定义的语言类型、规范类型、抽象操作 、语法产生式、内在对象和内在符号与本规范进行接口交互。
4.3 ECMAScript 概览
以下是对 ECMAScript 的非正式概览——并未描述语言的所有部分。此概览不属于标准正文的一部分。
ECMAScript 是基于对象的:基础语言设施和宿主 设施都由对象提供,而 ECMAScript 程序则是一组相互通信的对象。在 ECMAScript 中,对象 是由零个或多个属性 组成的集合,每个属性带有决定该属性如何被使用的特性 ——例如,当某个属性的 Writable 特性被设为 false 时,任何已执行的 ECMAScript 代码试图为该属性赋不同值的操作都会失败。属性是容器,用来保存其他对象、原始值 或函数 。原始值属于以下内建类型之一:Undefined 、Null 、Boolean 、Number 、BigInt 、String 和 Symbol; 对象属于内建类型 Object ;而函数则是可调用对象。通过属性与对象关联的函数称为方法 。
ECMAScript 定义了一组内建对象 ,以补全 ECMAScript 实体的定义。这些内建对象包括:全局对象 ;对语言运行时语义 至关重要的对象,包括 Object、Function、Boolean、Symbol 以及各种 Error 对象;表示和操作数值的对象,包括 Math、Number 和 Date;文本处理对象 String 和 RegExp;作为值索引集合的对象,包括 Array 以及九种不同类型的 Typed Array,它们的元素都具有特定的数值数据表示;键控集合,包括 Map 和 Set 对象;支持结构化数据的对象,包括 JSON 对象、ArrayBuffer、SharedArrayBuffer 和 DataView;支持控制抽象的对象,包括生成器函数和 Promise 对象;以及反射对象,包括 Proxy 和 Reflect。
ECMAScript 还定义了一组内建运算符 。ECMAScript 运算符包括各种一元运算、乘法运算符、加法运算符、位移运算符、关系运算符、相等运算符、二进制按位运算符、二进制逻辑运算符、赋值运算符以及逗号运算符。
大型 ECMAScript 程序可通过模块 获得支持,模块允许将程序划分为多个语句和声明序列。每个模块都会显式标识它使用且需要由其他模块提供的声明,以及它自身有哪些声明可供其他模块使用。
ECMAScript 语法有意与 Java 语法相似。ECMAScript 语法较为宽松,以便其可作为一种易用的脚本语言。例如,变量不要求声明其类型,属性也不关联类型,而已定义函数也不要求其声明在文本上出现在调用它们之前。
4.3.1 对象
尽管 ECMAScript 包含类定义语法,但 ECMAScript 对象在根本上并不像 C++、Smalltalk 或 Java 那样基于类。相反,对象可以通过多种方式创建,包括通过字面量表示法,或通过构造器 来创建对象,然后执行代码,通过给属性赋初值来初始化对象的全部或部分内容。每个构造器 都是一个函数,它具有名为 "prototype" 的属性,用于实现基于原型的继承 和共享属性 。对象通过在 new 表达式中使用构造器 来创建;例如,new Date(2009, 11) 会创建一个新的 Date 对象。不使用 new 调用构造器 会产生依构造器 而定的后果。例如,Date() 产生的是当前日期和时间的字符串表示,而不是对象。
每个由构造器 创建的对象都隐式引用其构造器 "prototype" 属性的值(称为该对象的原型 )。此外,一个原型还可能对其自身的原型有一个非 null 的隐式引用,如此继续;这被称为原型链 。当引用对象中的某个属性时,该引用指向原型链中第一个包含该名称属性的对象中的该属性。换言之,首先检查直接提到的对象是否有该属性;如果该对象包含该命名属性,则引用指向该属性;如果不包含,则继续检查该对象的原型;依此类推。
Figure 1: 对象/原型关系
在基于类的面向对象语言中,一般来说,状态由实例承载,方法由类承载,而继承仅涉及结构和行为。在 ECMAScript 中,状态和方法都由对象承载,而结构、行为和状态都会被继承。
所有那些自身不直接包含其原型所含某个特定属性的对象,都会共享该属性及其值。图 1 说明了这一点:
CF 是一个构造器 (同时也是一个对象)。通过使用 new 表达式创建了五个对象:cf1 、cf2 、cf3 、cf4 和 cf5 。这些对象中的每一个都包含名为 "q1" 和 "q2" 的属性。虚线表示隐式的原型关系;因此,例如,cf3 的原型是 CFp 。构造器 CF 自身有两个属性,名为 "P1" 和 "P2" ,它们对 CFp 、cf1 、cf2 、cf3 、cf4 和 cf5 都不可见。CFp 中名为 "CFP1" 的属性由 cf1 、cf2 、cf3 、cf4 和 cf5 共享(但不被 CF 共享);同样,CFp 的隐式原型链中找到的任何属性,只要名称不是 "q1" 、"q2" 或 "CFP1" ,也都会被共享。注意,CF 与 CFp 之间不存在隐式原型链接。
与大多数基于类的对象语言不同,属性可以通过给对象赋值而被动态添加。也就是说,构造器 并不要求为所构造对象的全部或任何属性命名或赋值。在上图中,可以通过给 CFp 中的某个属性赋新值,为 cf1 、cf2 、cf3 、cf4 和 cf5 增加一个新的共享属性。
尽管 ECMAScript 对象本质上并非基于类,但基于构造器 函数、原型对象和方法的通用模式来定义类式抽象通常是方便的。ECMAScript 内建对象本身就遵循这种类式模式。从 ECMAScript 2015 开始,ECMAScript 语言包含了类定义语法,使程序员能够简洁地定义符合与内建对象所使用的相同类式抽象模式的对象。
4.3.2 ECMAScript 的严格变体
ECMAScript 语言认识到,某些语言使用者可能希望限制自己对语言中某些可用特性的使用。他们这样做可能是出于安全考虑、为了避免他们认为容易出错的特性、为了获得更强的错误检查,或基于他们自己选择的其他原因。为支持这种可能性,ECMAScript 定义了语言的严格变体。语言的严格变体排除了常规 ECMAScript 语言中的某些特定语法和语义特性,并修改了某些特性的详细语义。严格变体还规定了额外的错误条件:在那些非严格形式语言未规定为错误的情形下,必须通过抛出错误异常来报告这些错误条件。
ECMAScript 的严格变体通常被称为语言的严格模式 。严格模式的选择,以及 ECMAScript 严格模式语法和语义的使用,是在单个 ECMAScript 源文本 单元的层级上显式作出的,如 11.2.2 所述。由于严格模式是在语法源文本单元层级选择的,因此严格模式只施加在此类源文本单元内具有局部效应的限制。严格模式不会限制或修改任何必须在多个源文本单元之间保持一致运作的 ECMAScript 语义方面。一个完整的 ECMAScript 程序可以由严格模式和非严格模式的 ECMAScript 源文本 单元共同组成。在这种情况下,严格模式仅在实际执行定义于严格模式源文本单元内的代码时适用。
为了符合本规范,ECMAScript 实现必须同时实现本规范所定义的完整不受限 ECMAScript 语言以及 ECMAScript 语言的严格变体。此外,实现还必须支持将不受限模式和严格模式的源文本单元组合成单个复合程序。
4.4 术语和定义
就本文档而言,以下术语和定义适用。
4.4.1 实现近似定义
实现近似定义 的设施,其定义全部或部分由外部来源给出,但本规范对其推荐了一种理想行为
4.4.2 实现定义
实现定义 的设施,其定义全部或部分由本规范之外的外部来源给出
4.4.3 宿主定义
与实现定义 相同
Note
4.4.4 类型
如条款 6 所定义的数据值集合
4.4.5 原始值
Undefined、Null、Boolean、Number、BigInt、Symbol 或 String 类型 中的成员,如条款 6 所定义
Note
4.4.6 对象
Object 类型 的成员
Note
对象是属性的集合,并且具有单个原型对象。该原型可以是 null 。
4.4.7 构造器
创建并初始化对象的函数对象
Note
构造器 的 "prototype" 属性值是一个原型对象,用于实现继承和共享属性。
4.4.8 原型
为其他对象提供共享属性的对象
Note
当构造器 创建对象时,该对象会为了解析属性引用而隐式引用构造器 的 "prototype" 属性。构造器 的 "prototype" 属性可以通过程序表达式 constructor .prototype 来引用,而添加到某个对象原型上的属性会通过继承被所有共享该原型的对象共享。另一种方式是,使用内建函数 Object.create 并显式指定原型来创建新对象。
4.4.9 普通对象
对于所有对象都必须支持的基本内部方法,具有默认行为的对象
4.4.10 异质对象
对于一个或多个基本内部方法,不具有默认行为的对象
Note
4.4.11 标准对象
其语义由本规范定义的对象
4.4.12 内建对象
由 ECMAScript 实现规定并提供的对象
Note
标准内建对象由本规范定义。ECMAScript 实现可以规定并提供额外种类的内建对象。
4.4.13 undefined 值
当变量尚未被赋值时所使用的原始值
4.4.14 Undefined 类型
其唯一值为 undefined 值的类型
4.4.15 null 值
表示刻意不存在任何对象值的原始值
4.4.16 Null 类型
其唯一值为 null 值的类型
4.4.17 Boolean 值
Boolean 类型 的成员
Note
Boolean 值只有两个:true 和 false 。
4.4.18 Boolean 类型
由原始值 true 和 false 构成的类型
4.4.19 Boolean 对象
Object 类型 的成员,且是标准内建 Boolean 构造器 的实例
Note
Boolean 对象通过在 new 表达式中使用 Boolean 构造器 并提供一个 Boolean 值作为参数来创建。所得对象具有一个内部槽,其值为该 Boolean 值。Boolean 对象可被强制转换为 Boolean 值。
4.4.20 String 值
由零个或多个 16 位无符号整数 值构成的有限 有序序列的原始值
Note
String 值是 String 类型 的成员。序列中的每个整数 值通常表示 UTF-16 文本中的一个 16 位单元。不过,ECMAScript 除要求这些值必须是 16 位无符号整数 外,不对这些值施加任何限制或要求。
4.4.21 String 类型
所有可能 String 值的集合
4.4.22 String 对象
Object 类型 的成员,且是标准内建 String 构造器 的实例
Note
String 对象通过在 new 表达式中使用 String 构造器 并提供一个 String 值作为参数来创建。所得对象具有一个内部槽,其值为该 String 值。String 对象可以通过将 String 构造器 作为函数调用而被强制转换为 String 值(22.1.1.1 )。
4.4.23 Number 值
对应于 IEEE 754-2019 双精度 64 位二进制格式值的原始值
Note
4.4.24 Number 类型
所有可能 Number 值 的集合,包括 NaN (“不是数字”)、+∞ 𝔽 (正无穷)和 -∞ 𝔽 (负无穷)
4.4.25 Number 对象
Object 类型 的成员,且是标准内建 Number 构造器 的实例
Note
Number 对象通过在 new 表达式中使用 Number 构造器 并提供一个 Number 值 作为参数来创建。所得对象具有一个内部槽,其值为该 Number 值 。Number 对象可以通过将 Number 构造器 作为函数调用而被强制转换为 Number 值 (21.1.1.1 )。
4.4.26 Infinity
表示正无穷 Number 值 的 Number 值
4.4.27 NaN
是 IEEE 754-2019 NaN(“不是数字”)值的 Number 值
4.4.28 BigInt 值
对应于任意精度整数 值的原始值
4.4.29 BigInt 类型
所有可能 BigInt 值 的集合
4.4.30 BigInt 对象
Object 类型 的成员,且是标准内建 BigInt 构造器 的实例
4.4.31 Symbol 值
表示唯一且非 String 的对象属性键 的原始值
4.4.32 Symbol 类型
所有可能 Symbol 值的集合
4.4.33 Symbol 对象
Object 类型 的成员,且是标准内建 Symbol 构造器 的实例
4.4.34 函数
Object 类型 的成员,可作为子程序被调用
Note
函数除了其属性之外,还包含可执行代码和状态,这些决定了它在被调用时的行为。函数的代码可以是 ECMAScript 编写的,也可以不是。
4.4.35 内建函数
作为函数的内建对象
Note
内建函数的例子包括 parseInt 和 Math.exp。宿主 或实现可以提供本规范未描述的额外内建函数。
4.4.36 内建构造器
作为构造器 的内建函数
Note
内建构造器 的例子包括 Object 和 Function。宿主 或实现可以提供本规范未描述的额外内建构造器 。
4.4.37 属性
对象的一部分,它关联一个键(String 值或 Symbol 值之一)和一个值
Note
根据属性形式的不同,该值可以直接表示为数据值(原始值、对象或函数对象 ),也可以通过一对访问器函数间接表示。
4.4.38 方法
作为属性值的函数
Note
当函数作为对象的方法被调用时,该对象会作为其 this 值传递给函数。
4.4.39 内建方法
作为内建函数的方法
Note
标准内建方法由本规范定义。宿主 或实现可以提供本规范未描述的额外内建方法。
4.4.40 特性
定义属性某种特征的内部值
4.4.41 自有属性
被其对象直接包含的属性
4.4.42 继承属性
对象的某个属性,它不是自有属性,但却是该对象原型的属性(无论是自有还是继承)
4.5 本规范的组织结构
本规范其余部分的组织如下:
条款 5 定义了贯穿本规范所使用的记号约定。
条款 6 到 10 定义了 ECMAScript 程序运行所处的执行环境。
条款 11 到 17 定义了实际的 ECMAScript 编程语言,包括其语法编码以及所有语言特性的执行语义。
条款 18 到 28 定义了 ECMAScript 标准库。它们包括所有标准对象的定义,这些对象可供 ECMAScript 程序在执行时使用。
条款 29 描述了基于 SharedArrayBuffer 的内存访问以及 Atomics 对象方法的内存一致性模型。