?
u
m
/
p
1-9
在 https://tc39.es/ecma262/ 上的文档是最准确和最新的ECMAScript规范。它包含了最新年度快照的内容以及任何已完成的提案(那些在提案流程中达到第4阶段并因此在多个实现中实现且将在下一次实际修订中包含的提案)自该快照以来的内容。
此规范在GitHub上由ECMAScript社区的帮助下开发。有多种方式可以为此规范的发展做出贡献:
有关如何创建此文档的更多信息,请参阅
此ecma标准定义了ECMAScript 2024语言。它是ECMAScript语言的第十五版 规范。自1997年第一版出版以来,ECMAScript已发展成为世界上 最广泛使用的通用编程语言。它最为人所知的是嵌入在网络中的语言 浏览器,但也被广泛用于服务器和嵌入式应用程序。
ECMAScript基于几种原始技术,最著名的是JavaScript(Netscape)和 JScript(微软)。该语言由Netscape的Brendan Eich发明,首次出现在该公司的 Navigator 2.0浏览器。它已出现在Netscape的所有后续浏览器和Netscape的所有浏览器中 Microsoft从Internet Explorer 3.0开始。
ECMAScript语言规范的开发始于1996年11月。这个的第一版 ECMA标准于1997年6月由ECMA大会通过。
该ECMA标准已提交给ISO/IEC JTC 1以供快速通道程序采用,并被批准为 国际标准ISO/IEC 16262,1998年4月。ECMA大会于1998年6月批准了第二个 ECMA-262版本,使其完全符合ISO/IEC 16262。第一个和第二个之间的变化 版本本质上是编辑性的。
标准第三版引入了强大的正则表达式、更好的字符串处理、新的控件 语句、try/catch异常处理、更严格的错误定义、数字输出的格式和次要 对未来语言增长的预期变化。ECMAScript标准的第三版被 1999年12月的ECMA大会,并于2002年6月作为ISO/IEC 16262:2002发布。
第三版发布后,ECMAScript与全球广泛采用 Web,它已成为基本上所有Web浏览器都支持的编程语言。重要的 开发ECMAScript第四版的工作已经完成。然而,这项工作没有完成,也没有出版 作为ECMAScript的第四版,但其中一些被纳入了第六版的开发。
ECMAScript第五版(作为ECMA-262 5th版发布)事实上已编纂
对浏览器实现中常见的语言规范的解释并添加了
支持自第三版出版以来出现的新功能。这些功能包括
第五版提交给ISO/IEC JTC 1采用快速通道程序,并被批准为国际标准ISO/IEC 16262:2011。ECMAScript标准的5.1版包含了一些小的修正,文本与ISO/IEC 16262:2011相同。5.1版于2011年6月被Ecma大会采纳。
第六版的集中开发始于2009年,当时第五版正在准备出版。然而,在此之前,自1999年第三版发布以来,已经进行了大量的实验和语言增强设计工作。从某种意义上说,第六版的完成是十五年努力的结晶。本版的目标包括提供对大型应用程序、库创建的更好支持,并将ECMAScript用作其他语言的编译目标。其主要增强功能包括模块、类声明、词法块作用域、迭代器和生成器、用于异步编程的Promises、解构模式和正确的尾调用。ECMAScript内置库扩展了对附加数据抽象的支持,包括地图、集合和二进制数值数组,并在字符串和正则表达式中增加了对Unicode补充字符的支持。内置库还通过子类化变得可扩展。第六版为常规的、增量的语言和库增强提供了基础。第六版于2015年6月被大会采纳。
ECMAScript 2016是Ecma TC39在新的年度发布节奏和开放开发流程下发布的第一个ECMAScript版本。从ECMAScript
2015源文档生成了一个纯文本源文档,作为在GitHub上进一步开发的基础。在这一标准的开发过程中,提交了数百个拉取请求和问题,代表了成千上万个错误修复、编辑修正和其他改进。此外,还开发了许多软件工具来帮助这一工作,包括Ecmarkup、Ecmarkdown和Grammarkdown。ES2016还包括对新幂运算符的支持,并在Array.prototype
中添加了一个名为includes
的新方法。
ECMAScript 2017引入了异步函数、共享内存和原子操作,以及一些较小的语言和库增强、错误修复和编辑更新。异步函数通过提供Promise返回函数的语法来改进异步编程体验。共享内存和原子操作引入了一种新的内存模型,允许多代理程序使用原子操作进行通信,即使在并行CPU上也能确保定义明确的执行顺序。它还包括Object上的新静态方法:Object.values
、Object.entries
和Object.getOwnPropertyDescriptors
。
ECMAScript
2018通过AsyncIterator协议和异步生成器引入了对异步迭代的支持。它还包括四个新的正则表达式特性:dotAll
标志、命名捕获组、Unicode属性转义和后行断言。最后,它还包括对象的剩余和扩展属性。
ECMAScript
2019引入了一些新的内置函数:Array.prototype
上的flat
和flatMap
用于扁平化数组,Object.fromEntries
用于直接将Object.entries
的返回值转化为新对象,以及String.prototype
上的trimStart
和trimEnd
作为更好命名的替代方案,取代广泛实现但非标准的String.prototype.trimLeft
和trimRight
内置函数。此外,它还包括一些语法和语义的较小更新。更新的语法包括可选的catch绑定参数,并允许在字符串字面量中使用U+2028(行分隔符)和U+2029(段落分隔符)以与JSON保持一致。其他更新包括要求Array.prototype.sort
为稳定排序,要求JSON.stringify
无论输入如何都返回格式良好的UTF-8,以及通过要求Function.prototype.toString
返回相应的原始源文本或标准占位符来进行明确。
ECMAScript
2020,第11版,引入了字符串的matchAll
方法,用于生成全局正则表达式匹配对象的迭代器;import()
语法,用于动态异步导入模块;BigInt
,一种新的数字原始类型,用于处理任意精度的整数;Promise.allSettled
,一种新的Promise组合器,不会短路;globalThis
,一种通用的全局this
值访问方式;专用的export * as ns from 'module'
语法,用于模块内;增加了for-in
枚举顺序的标准化;import.meta
,一个由宿主填充的对象,包含关于模块的上下文信息;以及为处理“nullish”值(
ECMAScript
2021,第12版,引入了字符串的replaceAll
方法;Promise.any
,一个在输入值被实现时短路的Promise组合器;AggregateError
,一种新错误类型,用于同时表示多个错误;逻辑赋值操作符(??=
、&&=
、||=
);WeakRef
,用于引用目标对象而不保留其免于垃圾回收,以及FinalizationRegistry
,用于管理在目标对象被垃圾回收时执行的清理操作的注册和取消注册;数字字面量的分隔符(1_000
);并且使Array.prototype.sort
更加精确,减少了导致
ECMAScript 2022,第13版,引入了顶层await
,允许在模块顶层使用关键字;新的类元素:公共和私有实例字段、公共和私有静态字段、私有实例方法和访问器、以及私有静态方法和访问器;类中的静态块,用于每类评估初始化;#x in obj
语法,用于测试对象上私有字段的存在;通过/d
标志的正则表达式匹配索引,提供匹配子字符串的起始和结束索引;Error
对象上的cause
属性,用于记录错误中的因果链;用于字符串、数组和类型化数组的at
方法,允许相对索引;以及Object.hasOwn
,Object.prototype.hasOwnProperty
的便捷替代。
ECMAScript
2023,第14版,引入了Array.prototype
和TypedArray.prototype
上的toSorted
、toReversed
、with
、findLast
和findLastIndex
方法,以及Array.prototype
上的toSpliced
方法;增加了对文件开头#!
注释的支持,以更好地促进可执行ECMAScript文件;并允许在弱集合中使用大多数符号作为键。
ECMAScript
2024,第15版,增加了调整和转移ArrayBuffers和SharedArrayBuffers大小的功能;添加了用于创建具有更高级功能的字符串集的RegExp/v
标志;引入了用于构建Promise的便捷方法Promise.withResolvers
、用于数据聚合的Object.groupBy
和Map.groupBy
方法、用于异步等待共享内存更改的Atomics.waitAsync
方法,以及用于检查和确保字符串仅包含格式良好的Unicode的String.prototype.isWellFormed
和String.prototype.toWellFormed
方法。
代表许多组织的数十个人在Ecma TC39中对这一版本的开发以及之前的版本做出了非常重要的贡献。此外,还出现了一个支持TC39的ECMAScript工作的活跃社区。这个社区审查了无数草案,提交了数千个错误报告,进行了实现实验,贡献了测试套件,并向全球开发者社区介绍了ECMAScript。不幸的是,不可能识别和感谢每一个为这项工作做出贡献的人和组织。
Allen Wirfs-Brock
ECMA-262,第六版项目编辑
Brian Terlson
ECMA-262,第七版至第十版项目编辑
Jordan Harband
ECMA-262,第十版至第十二版项目编辑
Shu-yu Guo
ECMA-262,第十二版至第十五版项目编辑
Michael Ficarra
ECMA-262,第十二版至第十五版项目编辑
Kevin Gibbons
ECMA-262,第十二版至第十五版项目编辑
本标准定义了ECMAScript 2024通用编程语言。
符合ECMAScript规范的实现必须提供并支持本规范中描述的所有类型、值、对象、属性、函数和程序语法及语义。
符合ECMAScript规范的实现必须按照最新版本的Unicode标准和ISO/IEC 10646解释源文本输入。
提供支持不同语言和国家的语言和文化习俗的应用编程接口(API)的符合ECMAScript规范的实现必须实现ECMA-402最新版本中与本规范兼容的接口。
符合ECMAScript规范的实现可以提供本规范中未描述的其他类型、值、对象、属性和函数。特别是,符合ECMAScript规范的实现可以为本规范中描述的对象提供本规范中未描述的属性和值。
符合ECMAScript规范的实现可以支持本规范中未描述的程序和正则表达式语法。特别是,符合ECMAScript规范的实现可以支持使用本规范第
符合ECMAScript规范的实现不得实现本规范第
符合ECMAScript规范的实现不得重新定义任何不是
符合ECMAScript规范的实现可以选择实现或不实现规范性可选的小节。如果实现了任何规范性可选行为,则必须实现包含的规范性可选条款中的所有行为。本规范中用彩色框中的“规范性可选”一词来表示规范性可选条款,如下所示。
示例条款内容。
符合ECMAScript规范的实现必须实现遗留小节,除非它们也被标记为规范性可选。遗留小节中指定的所有语言特性和行为都具有一个或多个不理想的特性。然而,它们在现有应用程序中的持续使用阻止了它们从本规范中删除。这些特性不被视为ECMAScript核心语言的一部分。程序员在编写新的ECMAScript代码时不应使用或假设这些特性和行为的存在。
示例条款内容。
示例条款内容。
下列引用文件对于本文档的应用是必不可少的。对于有日期的引用,仅适用于所引用的版本。对于无日期的引用,适用于引用文件的最新版本(包括任何修正案)。
Unicode 标准。
https://unicode.org/versions/latest
ISO/IEC 10646,信息技术 — 通用多八位编码字符集 (UCS) 加上修正案1:2005、修正案2:2006、修正案3:2008、修正案4:2008和其他修正案和勘误,或其后续版本。
ECMA-402,ECMAScript 国际化 API 规范,特别是与本规范版本相对应的年度版。
https://www.ecma-international.org/publications-and-standards/standards/ecma-402/
ECMA-404,JSON 数据交换格式。
https://www.ecma-international.org/publications-and-standards/standards/ecma-404/
本节包含 ECMAScript 语言的非规范性概述。
ECMAScript 是一种面向对象的编程语言,用于在 宿主环境 中执行计算和操作计算对象。本规范中定义的 ECMAScript 并不打算是计算自给自足的;实际上,本规范没有规定外部数据的输入或计算结果的输出。相反,预计 ECMAScript 程序的计算环境不仅会提供本规范中描述的对象和其他设施,还会提供某些环境特定的对象,这些对象的描述和行为超出了本规范的范围,只是表明它们可能提供某些属性可以从 ECMAScript 程序中访问和调用的函数。
ECMAScript 最初设计为一种脚本语言,但现已广泛用作通用编程语言。脚本语言 是一种用于操作、定制和自动化现有系统功能的编程语言。在这些系统中,有用的功能已经通过用户界面可用,脚本语言是将这些功能暴露给程序控制的机制。这样,现有系统就提供了一个对象和设施的 宿主环境,从而完善了脚本语言的功能。脚本语言旨在供专业和非专业程序员使用。
ECMAScript 最初设计为一种 Web 脚本语言,提供一种机制来在浏览器中使网页生动起来,并作为基于 Web 的客户端-服务器架构的一部分执行服务器计算。ECMAScript 现在用于为各种 宿主环境 提供核心脚本功能。因此,本文件中规定的核心语言与任何特定的 宿主环境 无关。
ECMAScript 的使用已经超出了简单的脚本编写,它现在用于许多不同环境和规模的全方位编程任务。随着 ECMAScript 使用范围的扩大,它提供的功能和设施也在扩展。ECMAScript 现在是一种功能齐全的通用编程语言。
Web浏览器为客户端计算提供了一个ECMAScript 宿主环境,包括表示窗口、菜单、弹出窗口、对话框、文本区域、锚点、框架、历史记录、Cookies以及输入/输出的对象。此外,宿主环境还提供了一种将脚本代码附加到事件(如焦点更改、页面和图像加载、卸载、错误和中止、选择、表单提交和鼠标操作)的方法。脚本代码出现在HTML中,显示的页面是用户界面元素和固定和计算文本及图像的组合。脚本代码对用户交互有反应,因此不需要主程序。
Web服务器为服务器端计算提供了不同的宿主环境,包括表示请求、客户端和文件的对象;以及锁定和共享数据的机制。通过结合使用浏览器端和服务器端脚本,可以在客户端和服务器之间分配计算,同时为基于Web的应用程序提供定制的用户界面。
每个支持ECMAScript的Web浏览器和服务器都提供自己的宿主环境,从而完成ECMAScript的执行环境。
为了帮助将ECMAScript集成到宿主环境中,本规范将某些功能的定义(例如,抽象操作)全部或部分地推迟到本规范之外的来源。在编辑上,本规范区分了以下几种推迟定义的方式。
实现是进一步定义附录D中列出的功能或那些标记为实现定义或实现近似的功能的外部来源。在非正式使用中,实现是指具体的人工制品,例如特定的网络浏览器。
实现定义的功能是指将其定义推迟到外部来源而没有进一步的限定。本规范对特定行为没有做出任何建议,符合规范的实现可以在本规范提出的约束范围内选择任何行为。
实现近似的功能是指将其定义推迟到外部来源,同时建议一种理想行为。虽然符合规范的实现可以在本规范提出的约束范围内选择任何行为,但鼓励它们尽量接近理想。一些数学操作,例如Math.exp
,属于实现近似。
宿主是进一步定义附录D中列出的功能,但不进一步定义其他实现定义或实现近似功能的外部来源。在非正式使用中,宿主是指以相同方式通过附录D与本规范接口的所有实现集,例如所有网络浏览器的集合。宿主通常是一个外部规范,例如WHATWG HTML (https://html.spec.whatwg.org/)。换句话说,宿主定义的功能通常在外部规范中进一步定义。
宿主挂钩 是一个由外部来源全部或部分定义的抽象操作。所有 宿主挂钩 必须列在附录 D 中。宿主挂钩 必须至少符合以下要求:
宿主定义 的功能是将其定义推迟到外部来源而没有进一步的限定,并列在附录 D 中。不是 宿主 的实现也可以提供 宿主定义 的功能定义。
宿主环境 是所有 宿主定义 功能的特定定义选择。宿主环境 通常包括允许获取输入和提供输出的对象或函数,作为 宿主定义 属性的一部分的 全局对象。
本规范遵循始终使用最具体术语的编辑约定。例如,如果一个功能是 宿主定义 的,则不应称其为 实现定义。
宿主和实现可以通过本规范中定义的语言类型、规范类型、抽象操作、语法生成、内在对象和内在符号与本规范接口。
以下是 ECMAScript 的非规范性概述,并未描述该语言的所有部分。该概述不属于标准的正式部分。
ECMAScript 是基于对象的:基本语言和宿主功能由对象提供,ECMAScript
程序是一个相互通信的对象集合。在 ECMAScript 中,对象 是具有零个或多个 属性 的集合,每个属性都有确定如何使用该属性的 特性 ——
例如,当属性的可写特性(Writable attribute)设置为
ECMAScript 定义了一组 内置对象,完善了 ECMAScript 实体的定义。这些内置对象包括 全局对象;对语言的 运行时语义 基本的对象,包括
Object
、Function
、Boolean
、Symbol
及各种 Error
对象;表示和操作数值的对象,包括 Math
、Number
和 Date
;处理文本的对象 String
和
RegExp
;值的索引集合的对象,包括 Array
和九种不同类型的元素具有特定数值表示的 Typed Arrays;键控集合,包括 Map
和 Set
对象;支持结构化数据的对象,包括 JSON
对象、ArrayBuffer
、SharedArrayBuffer
和 DataView
;支持控制抽象的对象,包括生成器函数和
Promise
对象;以及反射对象,包括 Proxy
和 Reflect
。
ECMAScript 还定义了一组内置 运算符。ECMAScript 运算符包括各种一元运算符、乘法运算符、加法运算符、位移运算符、关系运算符、相等运算符、二进制位运算符、二进制逻辑运算符、赋值运算符和逗号运算符。
大型 ECMAScript 程序由 模块 支持,允许程序划分为多个语句和声明的序列。每个模块明确标识其使用的需要由其他模块提供的声明,以及哪些声明可供其他模块使用。
ECMAScript 语法故意类似于 Java 语法。ECMAScript 语法被放宽,以使其作为一种易于使用的脚本语言。例如,变量不需要声明其类型,属性也没有关联类型,定义的函数也不需要在调用之前出现在文本上。
尽管 ECMAScript 包含类定义的语法,但 ECMAScript 对象并非如 C++、Smalltalk 或 Java 中的类为基础。相反,对象可以通过多种方式创建,包括字面量表示法或 构造函数,这些构造函数创建对象,然后通过为其属性分配初始值来初始化全部或部分对象。每个 构造函数 都是一个具有名为
new Date(2009, 11)
创建一个新的 Date 对象。不使用 new 调用 构造函数
会产生不同的结果,这取决于 构造函数。例如,Date()
生成当前日期和时间的字符串表示,而不是对象。
每个由 构造函数 创建的对象都有一个隐式引用(称为对象的
原型),指向其 构造函数 的
在基于类的面向对象语言中,通常状态由实例承载,方法由类承载,并且继承仅限于结构和行为。而在 ECMAScript 中,状态和方法由对象承载,而结构、行为和状态都是继承的。
所有不直接包含其原型所包含的特定属性的对象共享该属性及其值。图 1 说明了这一点:
CF 是一个 构造函数(也是一个对象)。通过使用
new
表达式创建了五个对象:cf1、cf2、cf3、cf4 和
cf5。这些对象每个都包含名为
与大多数基于类的对象语言不同,可以通过分配值动态地向对象添加属性。也就是说,构造函数 不需要命名或分配所有或任何构造对象的属性。在上图中,可以通过向 CFp 中的属性分配新值,为 cf1、cf2、cf3、cf4 和 cf5 添加一个新的共享属性。
尽管 ECMAScript 对象本质上不是基于类的,但根据 构造函数、原型对象和方法的共同模式定义类样抽象通常是方便的。ECMAScript 内置对象本身遵循这样的类样模式。从 ECMAScript 2015 开始,ECMAScript 语言包括语法类定义,允许程序员简洁地定义符合内置对象使用的相同类样抽象模式的对象。
ECMAScript 语言认识到某些用户可能希望限制其使用语言中某些功能的可能性。他们可能出于安全考虑,避免他们认为容易出错的功能,获得增强的错误检查,或出于其他原因。为了支持这种可能性,ECMAScript 定义了语言的严格变体。语言的严格变体排除了一些常规 ECMAScript 语言的特定语法和语义特性,并修改了某些特性的详细语义。严格变体还指定了在非严格形式的语言未指定为错误的情况下必须通过抛出错误异常来报告的其他错误条件。
ECMAScript 的严格变体通常称为语言的严格模式。严格模式的选择和 ECMAScript 严格模式语法和语义的使用明确在单个 ECMAScript 源文本 单元级别进行,如 11.2.2 中所述。由于在语法源文本单元级别选择严格模式,因此严格模式仅对该源文本单元内具有局部效果的限制。严格模式不会限制或修改必须在多个源文本单元之间一致操作的 ECMAScript 语义。完整的 ECMAScript 程序可以由严格模式和非严格模式 ECMAScript 源文本 单元组成。在这种情况下,严格模式仅在实际执行在严格模式源文本单元中定义的代码时才适用。
为了符合本规范,ECMAScript 实现必须实现完整的无限制 ECMAScript 语言和本规范定义的 ECMAScript 语言的严格变体。此外,实现必须支持将无限制和严格模式源文本单元组合成一个单一的组合程序。
在本文件中,适用以下术语和定义。
一个 实现近似 设施是由外部来源全部或部分定义的,但在本规范中有推荐的理想行为。
一个 实现定义 设施是由外部来源全部或部分定义的。
与 实现定义 相同。
编辑说明,参见 4.2 条款。
数据值集合,定义见
是 Undefined、Null、Boolean、Number、BigInt、Symbol 或 String 类型中的一个成员,定义见
原始值是在语言实现的最低层直接表示的数据。
Object 类型的成员。
对象是属性的集合,并且有一个单一的原型对象。原型可以是
构造函数的
为其他对象提供共享属性的对象。
具有所有对象必须支持的基本内部方法默认行为的对象
在一个或多个基本内部方法上不具有默认行为的对象
其语义由本规范定义的对象
由 ECMAScript 实现指定和提供的对象
标准内置对象在本规范中定义。ECMAScript 实现可以指定和提供其他种类的内置对象。
当变量未被赋值时使用的原始值
唯一值为
表示故意缺少任何对象值的原始值
唯一值为
属于
只有两个布尔值,
由原始值
属于
Boolean 对象是通过在 new
表达式中使用 Boolean
原始值,是一个
所有可能的字符串值的集合
对应双精度 64 位二进制格式
Number 值是
所有可能的 Number 值的集合,包括特殊的“非数值” (NaN) 值、正无穷大和负无穷大
属于
表示正无穷大的 Number 值
表示
对应任意精度
所有可能的 BigInt 值的集合
表示唯一的、非字符串对象
所有可能的 Symbol 值的集合
属于
除了它的属性之外,函数还包含可执行代码和状态,这些代码和状态决定了它在调用时的行为。函数的代码可以是 ECMAScript 编写的,也可以不是。
内置对象,是一个函数
内置函数的例子包括 parseInt
和 Math.exp
。
内置函数,是一个
对象的一部分,关联一个键(字符串值或 Symbol 值)和一个值
根据属性的形式,值可以直接表示为数据值(原始值、对象或
作为属性值的函数
当函数作为对象的方法调用时,对象会作为其
作为内置函数的方法
标准内置方法在本规范中定义。
定义属性某些特性的内部值
直接包含在对象中的属性
对象的属性,不是自有属性,但它是对象原型的属性(自有属性或继承属性)
本规范的其余部分组织如下:
第
第
第
第
第
一个上下文无关文法由若干生成式组成。每个生成式的左侧都有一个抽象符号,称为非终结符,右侧则是一系列零个或多个非终结符和终结符符号。对于每个文法,终结符号来自指定的字母表。
链生成式是右侧有且只有一个非终结符号以及零个或多个终结符号的生成式。
从一个由单个特殊非终结符组成的句子开始,称为目标符号,给定的上下文无关文法指定了一种语言,即通过不断将序列中的任何非终结符替换为其左侧为该非终结符的生成式的右侧所能产生的终结符号的(可能是无限的)集合。
ECMAScript 的词法文法在
除空白和注释外的输入元素构成 ECMAScript 语法文法的终结符,称为 ECMAScript 标记。这些标记是 ECMAScript 语言的 /*
…*/
的注释,不论是否跨越多行)不包含行终止符,则它同样会被丢弃;但如果
ECMAScript 的正则表达式文法在
词法和正则表达式文法的生成式通过两个冒号 “::” 作为分隔标点来区分。这两种文法共享一些生成式。
在
数值字符串文法的生成式通过三个冒号 “:::” 作为标点符号来区分,且从不用于解析源文本。
ECMAScript 的 句法文法 在
当要将代码点流解析为 ECMAScript
解析成功时,会构造一个 解析树,这是一个以根为起点的树结构,其中每个节点是一个 解析节点。每个解析节点都是文法中某个符号的实例;它表示可以从该符号派生的源文本范围。表示整个源文本的解析树的根节点是解析的
解析器的每次调用都会实例化新的解析节点,并且在解析相同源文本时永不重用。解析节点被认为是相同的解析节点,当且仅当它们表示相同的源文本范围,是相同文法符号的实例,并且是由同一次解析器调用生成的。
多次解析相同的字符串会导致不同的解析节点。例如,考虑:
let str = "1 + 1;";
eval(str);
eval(str);
每次调用 eval
都会将 str
的值转换为
句法文法的生成式通过使用一个冒号 “:” 作为标点符号来区分。
在
在某些情况下,为避免歧义,句法文法使用了泛化生成式,允许不形成有效 ECMAScript
在ECMAScript语法中,一些终结符号显示为固定宽度
字体。这些符号应当按照书写的样子准确出现在源文本中。以这种方式指定的所有终结符号码点都应被理解为来自基本拉丁块的适当Unicode码点,而不是来自其他Unicode范围的类似看起来的码点。终结符号中的一个码点不能通过\
在其终结符号是单个Unicode码点的语法中(即,词汇、RegExp和数值字符串语法),连续的多个固定宽度码点出现在一个生产中,是一种简单的速记,用于表示相同的码点序列,写作独立的终结符号。
例如,产生式:
是以下的简写形式:
相比之下,在句法语法中,连续的固定宽度码点构成一个单独的终结符号。
终结符号还有其他两种形式:
非终结符号显示为斜体类型。非终结(也称为“产生式”)的定义是由被定义的非终结名称开始,后面跟着一个或多个冒号(冒号的数量表示生产所属的语法)。然后,非终结的一个或多个备选右侧在后续行中跟随。例如,句法定义:
说明非终结while
,后跟一个左括号,然后是一个
说明一个
下标后缀“opt”,可出现在终结符或非终结符之后,表示一个可选符号。包含可选符号的替代项实际上指定了两个右侧,一个省略可选元素,一个包含它。这意味着:
是一个方便的缩写:
和:
是一个方便的缩写:
反过来又是一个缩写:
因此,在这个例子中,非终结符
一个产生式可能会被形式为“[parameters]”的下标注释参数化,它可能作为由产生式定义的非终结符号的后缀出现。“parameters”可以是单个名称或逗号分隔的名称列表。参数化的产生式是一组产生式的简写,这些产生式定义了所有参数名称的组合,这些名称由下划线前缀,并附加到参数化的非终结符号上。这意味着:
是以下的缩写:
并且:
是以下的缩写:
多个参数会产生组合数量的产生式,但并不是所有的产生式都必须在完整的语法中被引用。
产生式右侧的非终结符号的引用也可以被参数化。例如:
等同于说:
以及:
相当于:
一个非终结符的引用可能同时具有参数列表和“opt”后缀。例如:
是以下的缩写:
在右侧非终结符引用中,用“?”前缀参数名称,使得该参数值依赖于当前产生式左侧符号引用中参数名称的出现。例如:
是以下的缩写:
如果右侧的备选方案以“[+parameter]”为前缀,那么这个备选方案只在引用产生式的非终结符号时使用了指定的参数才可用。如果右侧的备选方案以“[~parameter]”为前缀,那么这个备选方案只在引用产生式的非终结符号时未使用指定的参数才可用。这意味着:
是以下的缩写:
并且:
是以下的缩写:
当语法定义中的冒号后面跟着“one of”这几个词时,它们表示接下来的每一行上的终结符号都是一个替代定义。例如,ECMAScript的词法语法包含以下产生式:
这只是一个方便的缩写,完整形式为:
如果产生式的右侧出现“[empty]”这一短语,它表示该产生式的右侧不包含任何终结符号或非终结符号。
如果短语“[lookahead = seq]”出现在产生式的右侧,它表示只有当令牌序列seq是紧随其后的输入令牌序列的前缀时,才能使用该产生式。类似地,“[lookahead ∈ set]”,其中set是一个非空的有限令牌序列集合,表示只有当set中的某个元素是紧随其后的令牌序列的前缀时,才能使用该产生式。为了方便起见,该集合也可以写作非终结符,这种情况下它代表所有非终结符可以扩展到的令牌序列的集合。如果非终结符可以扩展到无限多个不同的令牌序列,则被认为是编辑错误。
这些条件可以被否定。“[lookahead ≠ seq]”表示只有当seq不是紧随其后的输入令牌序列的前缀时,才能使用包含的产生式,“[lookahead ∉ set]”表示只有当set中的没有元素是紧随其后的令牌序列的前缀时,才能使用该产生式。
例如,给定以下定义:
定义如下:
匹配字母n
,后跟一个或多个十进制数字,第一个数字为偶数,或一个十进制数字,后面没有跟随另一个十进制数字。
注意,当这些短语在句法语法中使用时,可能无法明确识别紧随其后的令牌序列,因为确定后续的令牌需要知道在后续位置使用哪个词法目标符号。因此,当这些短语在句法语法中使用时,如果词法目标符号的选择可能会改变seq是否会成为生成的令牌序列的前缀,那么在前视限制中出现令牌序列seq(包括作为序列集合的一部分)被认为是编辑错误。
如果在句法文法的生成式右侧出现短语“[no
表示如果在脚本中 throw
标记和
除非受限生成式禁止出现
生成式的右侧可以使用短语“but not”并指示要排除的扩展来指定不允许某些扩展。例如,生成式:
意味着非终结符
最后,在一些列出所有替代方案不切实际的情况下,使用无衬线字体的描述性短语来描述少数非终结符号:
该规范经常使用编号列表来指定算法中的步骤。这些算法用于精确指定 ECMAScript 语言结构的所需语义。这些算法并不意味着必须使用任何特定的实现技术。实际上,可能有更有效的算法可用于实现给定的功能。
算法可以明确地用一个有序的、逗号分隔的别名序列参数化,这些别名在算法步骤中可用于引用在该位置传入的参数。可选参数用方括号([ , name
])表示,与算法步骤中的必需参数没有区别。参数列表的末尾可以出现一个剩余参数,以省略号(, ...name)表示。剩余参数捕获所有在必需参数和可选参数之后提供的参数,这些参数被编入一个
算法步骤可以细分为顺序子步骤。子步骤是缩进的,并且本身可以进一步分为缩进的子步骤。用大纲编号约定来标识子步骤,第一层子步骤用小写字母标记,第二层子步骤用小写罗马数字标记。如果需要超过三个层级,这些规则将重复,第四层使用数字标签。例如:
步骤或子步骤可以作为一个“if”谓词编写,条件化其子步骤。在这种情况下,只有当谓词为真时,子步骤才会被应用。如果步骤或子步骤以“else”一词开头,它是一个谓词,是与同一层级前一个“if”谓词步骤的否定。
步骤可以指定其子步骤的迭代应用。
以“Assert(断言):”开头的步骤断言其算法的不变条件。这种断言用来明确那些否则会是隐含的算法不变性。这样的断言不增加额外的语义要求,因此实现无需检查。它们仅用于澄清算法。
算法步骤可以使用“Let x be someValue”的形式声明任何值的命名别名。这些别名类似于引用,x和someValue都指向相同的底层数据,对任何一个的修改都对双方可见。如果算法步骤想要避免这种类似引用的行为,应该明确地复制右侧值:“Let x be a copy of someValue”创建了someValue的一个浅拷贝。
一旦声明,别名可以在任何后续步骤中被引用,并且不能从别名声明之前的步骤中被引用。别名可以使用“Set x to someOtherValue”的形式进行修改。
为了便于在本规范的多个部分中使用,一些算法被称为抽象操作,它们被命名并以参数化的函数形式编写,以便可以从其他算法中通过名称引用它们。抽象操作通常使用函数应用风格引用,如 OperationName(arg1, arg2)。一些抽象操作被视为类似类的规范抽象中多态分派的方法。这种类似方法的抽象操作通常使用方法应用风格引用,例如 someValue.OperationName(arg1, arg2)。
一个语法导向操作是一个命名操作,其定义包括多个算法,每个算法都与ECMAScript语法之一的一个或多个产生式相关联。具有多个替代定义的产生式通常会为每个替代定义有一个独特的算法。当一个算法与一个语法产生式相关联时,它可以引用产生式替代的终结符和非终结符,就好像它们是算法的参数一样。在这种方式下使用时,非终结符引用在解析源文本时匹配的实际替代定义。由语法产生式匹配的源文本或由其衍生的
当一个算法与一个产生式替代相关联时,该替代通常显示时不包括任何“[ ]”语法注释。这样的注释只应影响替代的语法识别,对替代的相关语义没有影响。
语法导向操作通过使用下列算法中的步骤
除非另有明确规定,所有
但是
运行时语义:
需要在运行时调用以指定语义的算法称为运行时语义。运行时语义由
抽象操作完成接受参数completionRecord(一个
算法步骤中提到抛出异常的,如:
意味着与以下内容相同:
算法步骤中提到或等同于以下内容:
意味着:
算法步骤中提到或等同于:
意味着:
hygienicTemp 是短暂的,仅在涉及 ReturnIfAbrupt 的步骤中可见。
算法步骤中提到或等同于:
意味着:
在?
表示应当应用
等同于以下步骤:
同样,对于方法应用风格,步骤:
等同于:
同样地,前缀!
用来表示以下对抽象或
等同于以下步骤:
!
或?
:
在声明返回
如果通过任何其他方式从这样的抽象操作中返回
意味着与任何一种
或
或
注意,通过
以下示例将是一个编辑错误,因为在该步骤中没有注明正在返回
无上下文语法并不足以表达所有定义流式输入元素是否形成可评估的 ECMAScript
静态语义规则具有名称,并通常使用算法定义。命名的静态语义规则与语法产生式相关联,具有多个备选定义的产生式通常对每个适用的命名静态语义规则有一个单独的算法。
静态语义规则的一种特殊类型是早期错误规则。
本规范参考以下数值类型:
在本规范的术语中,数值使用下标后缀来区分不同的数值类型。下标 𝔽 表示数字(Numbers),下标 ℤ 表示大整数(BigInts)。没有下标后缀的数值指代
数值运算符(如 +、×、= 和 ≥)根据操作数的类型确定其操作。当应用于
一般来说,当本规范提到数值时,例如“y 的长度”或“由四位十六进制数字表示的
不定义混合类型操作数(例如数字和
本规范中大多数数值以十进制表示;同时也使用形如 0x 后跟数字 0-9 或 A-F 的十六进制值。
当本规范中使用术语 整数 时,指的是在
本文档中对
数学函数
数学函数
记法 “
短语 "将 x 夹在 lower 和 upper 之间"(其中 x 是
数学函数
数学函数
数学函数
从下界 a 到上界 b 的 区间 是可能是无限的、可能为空的、相同数值类型的数值集合。每个边界都将描述为包含或排除,但不会同时包含。有四种类型的区间,如下所示:
例如,从 1(包含)到 2(排除)的
在本规范中,Function.prototype.apply
或 let n = 42;
区分开来。
在本规范中,规范值和
从本规范的角度来看,“is”一词用于比较两个值是否相等,例如“如果bool为
从 ECMAScript 语言的角度来看,语言值使用
对于规范值,没有规范身份的值包括但不限于:
规范身份对于所有
本规范中的算法操作值,每个值都有一个关联的类型。可能的值类型正是本条款中定义的那些类型。类型进一步分为
在本规范中,“Type(x)”表示“x的类型”,其中“类型”指的是本条款中定义的ECMAScript语言和规范类型。
ECMAScript 语言类型对应于由 ECMAScript 程序员直接使用 ECMAScript 语言操作的值。ECMAScript 语言类型包括 Undefined、Null、Boolean、String、Symbol、Number、BigInt 和 Object。一个ECMAScript 语言值是由 ECMAScript 语言类型特征化的值。
Undefined 类型恰好有一个值,称为
Null 类型恰好有一个值,称为
Boolean 类型表示具有两个值的逻辑实体,称为
String 类型是所有有序序列的集合,这些序列由零个或多个 16
位无符号
不解释 String 内容的 ECMAScript 操作不应用进一步的语义。对解释 String 值的操作将每个元素视为单个 UTF-16 代码单元。然而,ECMAScript 不限制这些代码单元的值或关系,因此进一步解释 String 内容为 UTF-16 编码的 Unicode 代码点序列的操作必须考虑到格式不正确的子序列。这些操作对于每个数值位于从 0xD800 到 0xDBFF(由 Unicode 标准定义为leading surrogate,或更正式地称为high-surrogate code unit)的代码单元,以及每个数值位于从 0xDC00 到 0xDFFF(定义为trailing surrogate,或更正式地称为low-surrogate code unit)的代码单元使用以下规则:
函数 String.prototype.normalize
(参见22.1.3.15)可以用来显式标准化一个字符串值。String.prototype.localeCompare
(参见22.1.3.12)在内部标准化字符串值,但其他操作不会隐式地标准化它们操作的字符串。操作结果除非另有说明,否则不受语言和/或地区的影响。
这种设计背后的理念是为了保持字符串的实现尽可能简单和高效。如果ECMAScript源代码文本处于规范形式C,只要它们不包含任何Unicode转义序列,字符串字面值也保证是标准化的。
在这个规范中,“字符串连接 A、B 等...”(每个参数是一个字符串值、代码单元或代码单元的序列)表示的是一个字符串值,其代码单元的序列是每个参数(按顺序)的代码单元的连接(按顺序)。
短语“从 inclusiveStart 到 exclusiveEnd 的 子字符串”(其中 S 是一个字符串值或代码单元序列,而 inclusiveStart 和 exclusiveEnd 是整数)表示由 S 的连续代码单元组成的字符串值,开始于索引 inclusiveStart 并在索引 exclusiveEnd 之前立即结束(当 inclusiveStart = exclusiveEnd 时为空字符串)。如果省略了“to”后缀,则使用 S 的长度作为 exclusiveEnd 的值。
短语“ASCII 单词字符”表示以下字符串值,它仅由 Unicode 基本拉丁语块中的每个字母和数字以及
U+005F(下划线)组成:
出于历史原因,它对各种算法具有重要意义。
抽象操作 StringIndexOf 接受参数 string(一个字符串)、searchValue(一个字符串)和 fromIndex
(一个非负
如果 searchValue 是空字符串且 fromIndex ≤ string 的长度,该算法返回 fromIndex。空字符串实际上在字符串中的每个位置都能找到,包括在最后一个码位之后。
如果 fromIndex 加上 searchValue 的长度大于 string 的长度,该算法总是返回 -1。
符号类型 是可以用作对象属性键的所有非字符串值的集合(
每个可能的符号值都是唯一且不可变的。
每个符号值不可变地持有一个关联的值,称为 [[Description]],它要么是
众所周知的符号是本规范算法明确引用的内建符号值。它们通常用作属性的键,这些属性的值作为规范算法的扩展点。除非另有说明,否则众所周知的符号值在所有
在本规范中,一个众所周知的符号用 @@name 的形式表示,其中“name”是
规范名称 | [[Description]] | 值和用途 |
---|---|---|
@@asyncIterator |
|
一个方法,返回对象的默认异步迭代器。由for -await -of 语句的语义调用。
|
@@hasInstance |
|
一个方法,确定构造函数对象是否将某个对象识别为其实例之一。由instanceof 运算符的语义调用。
|
@@isConcatSpreadable |
|
一个布尔值属性,如果为true,表示对象应通过Array.prototype.concat |
@@iterator |
|
一个方法,返回对象的默认迭代器。由for-of语句的语义调用。 |
@@match |
|
一个正则表达式方法,将正则表达式与字符串匹配。由String.prototype.match |
@@matchAll |
|
一个正则表达式方法,返回一个迭代器,该迭代器生成正则表达式与字符串匹配的所有结果。由String.prototype.matchAll |
@@replace |
|
一个正则表达式方法,替换字符串中的匹配子字符串。由String.prototype.replace |
@@search |
|
一个正则表达式方法,返回匹配正则表达式的字符串中的索引。由String.prototype.search |
@@species |
|
一个函数值属性,是用于创建派生对象的构造函数。 |
@@split |
|
一个正则表达式方法,在匹配正则表达式的索引处分割字符串。由String.prototype.split |
@@toPrimitive |
|
一个方法,将对象转换为相应的原始值。由 |
@@toStringTag |
|
一个字符串值属性,用于创建对象的默认字符串描述。由内建方法Object.prototype.toString |
@@unscopables |
|
一个对象值属性,其自身和继承的属性名称是从相关对象的with 环境绑定中排除的属性名称。
|
ECMAScript 有两种内建的数字类型:Number 和 BigInt。以下
由于数值类型通常不能在不损失精度或截断的情况下相互转换,ECMAScript语言不提供这些类型之间的隐式转换。在调用需要另一种类型的函数时,程序员必须显式调用 Number
和
BigInt
函数进行类型转换。
ECMAScript 的早期和后续版本为某些运算符提供了隐式数值转换,这可能会损失精度或
数字类型(Number type)具有精确的
18,437,736,874,454,810,627
(即 NaN
产生。)在一些实现中,外部代码可能能够检测到各种不同的非数值,但这种行为是
还有另外两个特殊值,分别称为 +Infinity
(或简单地
Infinity
)和 -Infinity
产生。)
其余的 18,437,736,874,454,810,624(即
注意,这里有一个 +0
(或简单地 0
)和 -0
产生。)
18,437,736,874,454,810,622(即
18,428,729,675,200,069,632(即
其中,s 可以是 1 或 -1,m 是一个
剩余的 9,007,199,254,740,990(即
其中,s 可以是 1 或 -1,m 是一个
注意,在 Number 类型中,所有不大于 2
一个
一些 ECMAScript 运算符只处理特定范围内的
抽象操作 Number::unaryMinus 接受参数 x(一个 Number),并返回一个 Number。调用时执行以下步骤:
抽象操作 Number::bitwiseNOT 接受参数 x(一个 Number),并返回一个
抽象操作 Number::exponentiate 接受参数 base(一个 Number)和 exponent(一个 Number),并返回一个
Number。它返回一个
当 base 是 **
exponent 的结果与
抽象操作 Number::multiply 接受参数 x(一个 Number)和 y(一个 Number),返回一个 Number。它根据
抽象操作 Number::divide 接受参数 x(一个 Number)和 y(一个 Number),返回一个 Number。
它根据
抽象操作 Number::remainder 接受参数 n(一个 Number)和 d(一个 Number),返回一个 Number。 它返回其操作数的隐含除法的余数,其中 n 是被除数,d 是除数。调用时执行以下步骤:
在 C 和 C++ 中,取余运算符只接受整数操作数;在 ECMAScript 中,它也接受浮点操作数。
%
运算符计算的“余数”操作不同,后者由 %
以类似于 Java 抽象操作 Number::add 接受参数 x(一个 Number)和 y(一个 Number),返回一个
Number。它根据
抽象操作 Number::subtract 接受参数 x(一个 Number)和 y(一个 Number),返回一个 Number。它执行减法运算,生成其操作数的差;x 是被减数,y 是减数。调用时执行以下步骤:
总是有 x - y
的结果与 x + (-y)
相同。
抽象操作 Number::leftShift 接受参数 x(一个 Number)和 y(一个 Number),返回一个整数 Number。调用时执行以下步骤:
抽象操作 Number::signedRightShift 接受参数 x(一个 Number)和 y(一个 Number),返回一个整数 Number。调用时执行以下步骤:
抽象操作 Number::unsignedRightShift 接受参数 x(一个 Number)和 y(一个 Number),返回一个整数 Number。调用时执行以下步骤:
抽象操作 Number::lessThan 接受参数 x(一个 Number)和 y(一个 Number),返回一个布尔值或
抽象操作 Number::equal 接受参数 x(一个 Number)和 y(一个 Number),返回一个布尔值。调用时执行以下步骤:
抽象操作 Number::sameValue 接受参数 x(一个 Number)和 y(一个 Number),返回一个布尔值。调用时执行以下步骤:
抽象操作 Number::sameValueZero 接受参数 x(一个 Number)和 y(一个 Number),返回一个布尔值。调用时执行以下步骤:
抽象操作 Number::NumberBitwiseOp 接受参数 op(&
、^
或
|
)、x(一个 Number)和 y(一个 Number),返回一个
&
,则^
,则|
。
抽象操作 Number::bitwiseAND 接受参数 x(一个 Number)和 y(一个 Number),返回一个
&
,
x, y).
抽象操作 Number::bitwiseXOR 接受参数 x(一个 Number)和 y(一个 Number),返回一个
^
,
x, y).
抽象操作 Number::bitwiseOR 接受参数 x(一个 Number)和 y(一个 Number),返回一个
|
,
x, y).
抽象操作 Number::toString 接受参数 x(一个数字)和 radix(一个在 2 到 36 之间的整数),并返回一个字符串。它使用以
radix 为基数的进位制系统将 x 表示为字符串。使用基数 r 表示数字时所用的数字取自
1.2e+3
。
ECMAScript 的实现者可能会发现 David M. Gay 撰写的关于浮点数二进制到十进制转换的论文和代码很有用:
Gay, David M. 正确舍入的二进制-十进制和十进制-二进制转换。数值分析,手稿 90-10。AT&T 贝尔实验室(新泽西州默里山)。1990 年 11 月 30 日。
可在
http://ampl.com/REFS/abstracts.html#rounding
获取。
相关代码可在
http://netlib.sandia.gov/fp/dtoa.c 和
http://netlib.sandia.gov/fp/g_fmt.c 获取,并且可能在各个
netlib
镜像站点上找到。
BigInt 类型 表示一个
抽象操作 BigInt::unaryMinus 接受参数 x(一个 BigInt)并返回一个 BigInt。它在被调用时执行以下步骤:
抽象操作 BigInt::bitwiseNOT 接受参数 x(一个 BigInt)并返回一个 BigInt。 它返回 x 的按位取反。它在被调用时执行以下步骤:
抽象操作 BigInt::exponentiate 接受参数 base(一个 BigInt)和 exponent(一个 BigInt),并返回一个包含 BigInt 的正常完成或抛出完成。它在被调用时执行以下步骤:
抽象操作 BigInt::multiply 接受参数 x(一个 BigInt)和 y(一个 BigInt)并返回一个 BigInt。它在被调用时执行以下步骤:
抽象操作 BigInt::divide 接受参数 x(一个 BigInt)和 y(一个 BigInt),并返回一个包含 BigInt 的正常完成或抛出完成。它在被调用时执行以下步骤:
抽象操作 BigInt::remainder 接受参数 n(一个 BigInt)和 d(一个 BigInt),并返回一个
抽象操作 BigInt::add 接受参数 x(一个 BigInt)和 y(一个 BigInt)并返回一个 BigInt。它在被调用时执行以下步骤:
抽象操作 BigInt::subtract 接受参数 x(一个 BigInt)和 y(一个 BigInt)并返回一个 BigInt。它在被调用时执行以下步骤:
抽象操作 BigInt::leftShift 接受参数 x(一个 BigInt)和 y(一个 BigInt)并返回一个 BigInt。它在被调用时执行以下步骤:
抽象操作 BigInt::signedRightShift 接受参数 x(一个 BigInt)和 y(一个 BigInt)并返回一个 BigInt。它在被调用时执行以下步骤:
抽象操作 BigInt::unsignedRightShift 接受参数 x(一个 BigInt)和 y(一个 BigInt)并返回一个
抽象操作 BigInt::lessThan 接受参数 x(一个 BigInt)和 y(一个 BigInt)并返回一个布尔值。它在被调用时执行以下步骤:
抽象操作 BigInt::equal 接受参数 x(一个 BigInt)和 y(一个 BigInt)并返回一个布尔值。它在被调用时执行以下步骤:
抽象操作 BinaryAnd 接受参数 x(0 或 1)和 y(0 或 1)并返回 0 或 1。它在被调用时执行以下步骤:
抽象操作 BinaryOr 接受参数 x(0 或 1)和 y(0 或 1)并返回 0 或 1。它在被调用时执行以下步骤:
抽象操作 BinaryXor 接受参数 x(0 或 1)和 y(0 或 1)并返回 0 或 1。它在被调用时执行以下步骤:
抽象操作 BigInt位运算 接受参数 op(&
、
^
或 |
)、x(一个 BigInt)和 y(一个 BigInt)并返回一个
BigInt。它在被调用时执行以下步骤:
&
,那么
|
,那么