页面模式偏好

4 概述

本节包含 ECMAScript 语言的非规范性概述。

ECMAScript 是一种面向对象的编程语言,用于在宿主环境中执行计算和操作计算对象。此处定义的 ECMAScript 并不打算在计算方面自给自足;事实上,本规范没有对外部数据的输入或计算结果的输出做出规定。相反,ECMAScript 程序的计算环境应当不仅提供本规范描述的对象和其他功能,还提供某些环境特有的对象;这些对象的描述和行为超出了本规范的范围,本规范仅指出,它们可以提供某些可由 ECMAScript 程序访问的属性和可由其调用的函数。

ECMAScript 最初被设计为脚本语言,但如今已被广泛用作通用编程语言。脚本语言是一种用于操作、定制现有系统的功能并使其自动化的编程语言。在这样的系统中,用户界面已经提供了有用的功能,而脚本语言则是一种将这些功能开放给程序控制的机制。因此,可以说现有系统提供了一个包含对象和功能的宿主环境,以补全脚本语言的能力。脚本语言旨在供专业和非专业程序员使用。

ECMAScript 最初被设计为一种 Web 脚本语言,提供了使浏览器中的 Web 页面具有动态效果,以及作为基于 Web 的客户端—服务器架构的一部分执行服务器计算的机制。如今,ECMAScript 被用于为各种宿主环境提供核心脚本能力。因此,本文档独立于任何特定宿主环境来规定核心语言。

ECMAScript 的用途已超出简单的脚本编写,如今被用于许多不同环境和规模中的各种编程任务。随着 ECMAScript 用途的扩展,它提供的特性和功能也不断增加。ECMAScript 如今已是一种功能完备的通用编程语言。

4.1 Web 脚本编程

Web 浏览器为客户端计算提供 ECMAScript 宿主环境,例如,其中包含表示窗口、菜单、弹出窗口、对话框、文本区域、锚点、框架、历史记录、Cookie 和输入/输出的对象。此外,宿主环境还提供了将脚本代码关联到事件的方式,这些事件包括焦点更改、页面和图像加载、卸载、错误和中止、选择、表单提交以及鼠标操作。脚本代码出现在 HTML 中,显示的页面则由用户界面元素以及固定和计算生成的文本与图像组合而成。脚本代码响应用户交互,无需主程序。

Web 服务器为服务器端计算提供不同的宿主环境,其中包括表示请求、客户端和文件的对象,以及锁定和共享数据的机制。通过结合使用浏览器端和服务器端脚本,可以在客户端与服务器之间分配计算任务,同时为基于 Web 的应用提供定制的用户界面。

每个支持 ECMAScript 的 Web 浏览器和服务器都提供自己的宿主环境,从而补全 ECMAScript 执行环境。

4.2 宿主和实现

为了便于将 ECMAScript 集成到宿主环境中,本规范将某些功能(例如抽象操作)的全部或部分定义交由本规范之外的来源提供。在编辑表述上,本规范区分以下几种定义委托方式。

实现是进一步定义附录 D 中列举的功能,或标记为实现定义或实现近似的功能的外部来源。在非正式用法中,实现指具体的软件产物,例如某个特定的 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 和九种不同的类型化数组,其元素均具有特定的数值数据表示;键控集合,包括 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 隐式引用,依此类推;这称为原型链。当引用对象中的某个属性时,该引用指向原型链中第一个包含该名称属性的对象上的同名属性。换言之,首先检查直接指定的对象是否具有该属性;如果该对象包含指定名称的属性,该引用就指向这个属性;如果该对象不包含指定名称的属性,则接着检查该对象的原型;依此类推。

图 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 的严格变体通常称为该语言的严格模式。如 11.2.2 所述,严格模式的选择以及 ECMAScript 严格模式语法和语义的使用,是在单个 ECMAScript 源文本单元级别显式确定的。由于严格模式是在语法源文本单元级别选择的,因此严格模式仅施加在该源文本单元内部局部生效的限制。严格模式不会限制或修改 ECMAScript 语义中必须在多个源文本单元之间一致运作的任何方面。完整的 ECMAScript 程序可以同时由严格模式和非严格模式的 ECMAScript 源文本单元组成。在这种情况下,严格模式仅在实际执行严格模式源文本单元中定义的代码时适用。

为符合本规范,ECMAScript 实现必须同时实现本规范所定义的完整、不受限制的 ECMAScript 语言及其严格变体。此外,实现必须支持将不受限制的源文本单元和严格模式源文本单元组合为单个复合程序。

4.4 术语和定义

以下术语和定义适用于本文档。

4.4.1 实现近似

实现近似的功能由外部来源全部或部分定义,但本规范为其建议了一种理想行为

4.4.2 实现定义

实现定义的功能由本规范之外的来源全部或部分定义

4.4.3 宿主定义

与实现定义相同

注

有关编辑表述上的区分,请参见 4.2 节。

4.4.4 类型

6 节所定义的数据值的集合

4.4.5 原始值

6 节所定义的 Undefined、Null、Boolean、Number、BigInt、Symbol 或 String 类型之一的成员

注

原始值是在语言实现的最底层直接表示的数据项。

4.4.6 对象

Object 类型的成员

注

对象是属性的集合,并具有单个原型对象。原型可以是 null。

4.4.7 构造函数

创建并初始化对象的函数对象

注

构造函数的 "prototype" 属性值是一个原型对象,用于实现继承和共享属性。

4.4.8 原型

为其他对象提供共享属性的对象

注

当构造函数创建对象时,该对象会隐式引用构造函数的 "prototype" 属性,以便解析属性引用。程序表达式 constructor.prototype 可以引用构造函数的 "prototype" 属性,而添加到对象原型上的属性会通过继承由所有共享该原型的对象共享。或者,可以使用内置函数 Object.create 创建一个具有显式指定原型的新对象。

4.4.9 普通对象

对于所有对象都必须支持的基本内部方法具有默认行为的对象

4.4.10 异质对象

对于一个或多个基本内部方法不具有默认行为的对象

注

任何不是普通对象的对象都是异质对象。

4.4.11 标准对象

其语义由本规范定义的对象

4.4.12 内置对象

由 ECMAScript 实现规定并提供的对象

注

标准内置对象由本规范定义。ECMAScript 实现可以规定并提供其他种类的内置对象。

4.4.13 undefined 值

变量尚未被赋值时使用的原始值

4.4.14 Undefined 类型

唯一值为 undefined 值的类型

4.4.15 null 值

表示有意不存在任何对象值的原始值

4.4.16 Null 类型

唯一值为 null 值的类型

4.4.17 Boolean 值

Boolean 类型的成员

注

Boolean 值只有两个:true 和 false。

4.4.18 Boolean 类型

由原始值 true 和 false 组成的类型

4.4.19 Boolean 对象

Object 类型的成员,是标准内置 Boolean 构造函数的实例

注

Boolean 对象通过在 new 表达式中使用 Boolean 构造函数并提供一个 Boolean 值作为参数来创建。生成的对象具有一个内部槽,其值为该 Boolean 值。Boolean 对象可以被强制转换为 Boolean 值。

4.4.20 String 值

由零个或多个 16 位无符号整数值组成的有限有序序列形式的原始值

注

String 值是 String 类型的成员。序列中的每个整数值通常表示 UTF-16 文本的单个 16 位单元。然而,除了要求这些值必须是 16 位无符号整数之外,ECMAScript 不对它们施加任何限制或要求。

4.4.21 String 类型

所有可能的 String 值的集合

4.4.22 String 对象

Object 类型的成员,是标准内置 String 构造函数的实例

注

String 对象通过在 new 表达式中使用 String 构造函数并提供一个 String 值作为参数来创建。生成的对象具有一个内部槽,其值为该 String 值。通过将 String 构造函数作为函数调用,可以将 String 对象强制转换为 String 值(22.1.1.1)。

4.4.23 Number 值

对应于 IEEE 754-2019 双精度 64 位二进制格式值的原始值

注

Number 值是 Number 类型的成员,是数值的直接表示。

4.4.24 Number 类型

所有可能的 Number 值的集合,包括 NaN(“非数值”)、+∞𝔽(正无穷)和 -∞𝔽(负无穷)

4.4.25 Number 对象

Object 类型的成员,是标准内置 Number 构造函数的实例

注

Number 对象通过在 new 表达式中使用 Number 构造函数并提供一个 Number 值作为参数来创建。生成的对象具有一个内部槽,其值为该 Number 值。通过将 Number 构造函数作为函数调用,可以将 Number 对象强制转换为 Number 值(21.1.1.1)。

4.4.26 Infinity

表示正无穷的 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 类型成员

注

除属性外,函数还包含可执行代码和状态,它们决定函数被调用时的行为。函数的代码可以用 ECMAScript 编写,也可以不用 ECMAScript 编写。

4.4.35 内置函数

属于函数的内置对象

注

内置函数的示例包括 parseInt 和 Math.exp。宿主或实现可以提供本规范未描述的其他内置函数。

4.4.36 内置构造函数

属于构造函数的内置函数

注

内置构造函数的示例包括 Object 和 Function。宿主或实现可以提供本规范未描述的其他内置构造函数。

4.4.37 属性

对象中将键(String 值或 Symbol 值)与值关联起来的部分

注

根据属性的形式,值可以直接表示为数据值(原始值、对象或函数对象),也可以通过一对访问器函数间接表示。

4.4.38 方法

作为属性值的函数

注

当函数作为对象的方法被调用时,该对象会作为函数的 this 值传递给函数。

4.4.39 内置方法

属于内置函数的方法

注

标准内置方法由本规范定义。宿主或实现可以提供本规范未描述的其他内置方法。

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 对象的方法。