4 概述
本节包含 ECMAScript 语言的非规范性概述。
ECMAScript 是一种面向对象的编程语言,用于在宿主环境中进行计算和操作计算对象。本规范中的 ECMAScript 并不旨在具备完全自给自足的计算能力;实际上,本规范未为外部数据输入或计算结果输出提供规定。而是预期 ECMAScript 程序的计算环境不仅提供本规范描述的对象和其他机制,还提供某些特定于环境的对象,其描述和行为超出本规范范围,仅说明它们可以提供可访问的属性和可从 ECMAScript 程序调用的函数。
ECMAScript 最初设计为脚本语言,但现已广泛用作通用编程语言。脚本语言是用于操作、定制和自动化现有系统功能的编程语言。在此类系统中,实用功能通常通过用户界面提供,脚本语言则是让程序能够控制这些功能的机制。这样,现有系统就提供了对象和机制组成的宿主环境,补足了脚本语言的能力。脚本语言面向专业和非专业程序员。
ECMAScript 最初设计为Web 脚本语言,用于在浏览器中为 Web 页面赋予动态行为,并在基于 Web 的客户端-服务器架构中执行服务器端计算。如今,ECMAScript 被用于为多种宿主环境提供核心脚本能力。因此,核心语言在本文件中独立于任何特定宿主环境进行描述。
ECMAScript 的使用已超越简单脚本,现在在许多环境和规模下用于各类编程任务。随着 ECMAScript 应用范围的扩大,其所提供的特性和机制也不断丰富。ECMAScript 现已成为功能完备的通用编程语言。
4.1 Web 脚本
网页浏览器为客户端计算提供 ECMAScript 宿主环境,例如用于表示窗口、菜单、弹窗、对话框、文本区域、锚点、框架、历史、Cookie 和输入/输出的对象。此外,宿主环境提供了将脚本代码绑定到事件的方法,如焦点变化、页面和图片加载、卸载、错误和中断、选择、表单提交和鼠标操作。脚本代码出现在 HTML 内,显示的页面是用户界面元素与固定及计算文本和图片的结合。脚本代码响应用户交互,无需主程序。
Web 服务器则为服务端计算提供不同的宿主环境,包括用于表示请求、客户端和文件的对象,以及锁定与共享数据的机制。通过结合浏览器端和服务器端脚本,可以在客户端和服务器间分布计算,同时为 Web 应用提供定制化用户界面。
支持 ECMAScript 的每个 Web 浏览器和服务器都提供自己的宿主环境,完善了 ECMAScript 的执行环境。
4.2 宿主和实现
为便于将 ECMAScript 集成到宿主环境中,本规范将某些机制(如抽象操作)全部或部分定义留给规范外部的来源。本规范在编辑上区分如下几种委托方式。
实现指的是进一步定义附件 D 列举的机制,或被标记为实现自定义或实现近似的机制的外部来源。在非正式用法中,实现通常指某个具体产物,如某个网页浏览器。
实现自定义指将某个机制的定义无附加限定地委托给外部来源。本规范未对具体行为做任何建议,符合规范的实现可在规范约束范围内自由选择行为。
实现近似指将某个机制的定义委托给外部来源,同时建议理想行为。符合规范的实现可在规范约束范围内自由选择行为,但鼓励尽量接近理想。例如部分数学操作,如 Math.exp
,采用实现近似方式。
宿主指进一步定义附件 D 所列机制,但不进一步定义其他实现自定义或近似机制的外部来源。在非正式用法中,宿主指以相同方式通过附件 D 与本规范接口的所有实现集合,如所有网页浏览器。宿主通常是外部规范,如 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 源文本单元级进行,如 11.2.2 所述。由于严格模式在语法源文本单元级选择,严格模式仅在该单元内产生局部影响。严格模式不会限制或修改必须跨多个源文本单元一致运行的 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 构造函数作为函数调用(22.1.1.1)被强制转换为 String 值。
4.4.23 Number 值
与双精度 64 位二进制格式 IEEE 754-2019 值对应的原始值
Note
Number 值属于 Number 类型,是数字的直接表示。
4.4.24 Number 类型
所有可能的 Number 值集合,包括 NaN(非数字)、+∞𝔽(正无穷)、-∞𝔽(负无穷)
4.4.25 Number 对象
属于 Object 类型且为标准内建 Number 构造函数实例的成员
Note
Number 对象通过在 new
表达式中使用 Number 构造函数并传递 Number 值参数创建。生成的对象有一个内部插槽,值为 Number 值。Number 对象可通过将 Number 构造函数作为函数调用(21.1.1.1)被强制转换为 Number 值。
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 类型,可作为子程序调用的成员
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 对象的方法。