5.1 句法和词法语法
5.1.1 上下文无关语法
上下文无关语法由若干产生式组成。每个产生式都有一个称为非终结符的抽象符号作为其左手边,并有零个或多个非终结符和终结符符号构成的序列作为其右手边。对于每种语法,终结符符号取自指定字母表。
链式产生式是指其右手边恰好有一个非终结符符号并伴随零个或多个终结符符号的产生式。
从一个仅由单个特定非终结符组成的句子开始,该非终结符称为目标符号,给定的上下文无关语法指定一种语言,即通过反复将序列中的任意非终结符替换为以该非终结符为左手边的产生式的右手边而可能得到的终结符符号序列的(也许是无限的)集合。
5.1.2 词法语法和 RegExp 语法
ECMAScript 的词法语法在条款 12 中给出。该语法以符合 11.1 中定义的 SourceCharacter 规则的 Unicode 码点作为其终结符符号。它定义了一组产生式,从目标符号 InputElementDiv、InputElementTemplateTail、InputElementRegExp、InputElementRegExpOrTemplateTail 或 InputElementHashbangOrRegExp 开始,描述此类码点序列如何被翻译为输入元素序列。
除空白和注释之外的输入元素构成 ECMAScript 句法语法的终结符符号,并称为 ECMAScript token。这些 token 是 ECMAScript 语言的保留字、标识符、字面量和 punctuators。此外,行终止符虽然不被认为是 token,但也会成为输入元素流的一部分,并指导自动分号插入过程(12.10)。简单空白和单行注释会被丢弃,且不会出现在句法语法的输入元素流中。MultiLineComment(即形如 /*…*/ 的注释,不论其是否跨越多行)如果不包含行终止符,同样会被简单丢弃;但如果 MultiLineComment 包含一个或多个行终止符,则它会被替换为单个行终止符,该行终止符成为句法语法的输入元素流的一部分。
ECMAScript 的 RegExp 语法在 22.2.1 中给出。该语法也以由 SourceCharacter 定义的码点作为其终结符符号。它定义了一组产生式,从目标符号 Pattern 开始,描述码点序列如何被翻译为正则表达式模式。
词法语法和 RegExp 语法的产生式以两个冒号“::”作为分隔标点来区分。词法语法和 RegExp 语法共享一些产生式。
5.1.3 数值字符串语法
数值字符串语法出现在 7.1.4.1 中。它以 SourceCharacter 作为其终结符符号,并用于从目标符号 StringNumericLiteral 开始将 Strings 翻译为数值(该语法类似于但不同于数值字面量的词法语法)。
数值字符串语法的产生式以三个冒号“:::”作为标点来区分,并且从不用于解析源文本。
5.1.4 句法语法
ECMAScript 的句法语法在条款 13 到 16 中给出。该语法以词法语法定义的 ECMAScript token 作为其终结符符号(5.1.2)。它定义了一组产生式,从两个可选目标符号 Script 和 Module 开始,描述 token 序列如何构成句法正确的 ECMAScript 程序独立组件。
当码点流将被解析为 ECMAScript Script 或 Module 时,它首先通过重复应用词法语法转换为输入元素流;然后该输入元素流通过一次应用句法语法来解析。如果输入元素流中的 token 不能被解析为目标非终结符(Script 或 Module)的单个实例且没有剩余 token,则输入流在句法上有错误。
解析成功时,会构造一棵解析树,即一种根树结构,其中每个节点都是一个 Parse Node。每个 Parse Node 都是语法中某个符号的实例;它表示可从该符号派生出的源文本跨度。解析树的根节点表示整个源文本,是该解析目标符号的实例。当 Parse Node 是非终结符的实例时,它也是某个以该非终结符为左手边的产生式的实例。此外,它有零个或多个子节点,产生式右手边的每个符号对应一个子节点:每个子节点都是对应符号的实例的 Parse Node。
每次调用解析器都会实例化新的 Parse Nodes,并且即使源文本相同,也绝不会在不同解析之间复用 Parse Nodes。当且仅当 Parse Nodes 表示相同的源文本跨度、是相同语法符号的实例,并且来自同一次解析器调用时,才认为它们是同一 Parse Node。
Note 1
多次解析同一个 String 会导致不同的 Parse Nodes。例如,考虑:
let str = "1 + 1;";
eval(str);
eval(str);
每次对 eval 的调用都会将 str 的值转换为 ECMAScript 源文本,并执行一次独立解析,创建其自身独立的 Parse Nodes 树。即使每次解析都作用于由同一个 String 值派生出的源文本,这些树也是不同的。
Note 2Parse Nodes 是规范制品,实现不要求使用类似的数据结构。
句法语法的产生式以仅一个冒号“:”作为标点来区分。
条款 13 到 16 中呈现的句法语法,并不完整说明哪些 token 序列会被接受为正确的 ECMAScript Script 或 Module。某些额外的 token 序列也会被接受,即如果只在序列的某些位置(例如行终止符字符之前)添加分号就会由语法描述的那些 token 序列。此外,如果行终止符字符出现在某些“尴尬”的位置,某些由语法描述的 token 序列也不被认为是可接受的。
在某些情况下,为避免歧义,句法语法使用广义产生式,这些产生式允许并不构成有效 ECMAScript Script 或 Module 的 token 序列。例如,这种技术用于对象字面量和对象解构模式。在这类情况下,会提供更具限制性的补充语法,以进一步限制可接受的 token 序列。通常,早期错误规则随后会说明,在某些上下文中,“p must cover an n”,其中 p 是 Parse Node(广义产生式的一个实例),而 n 是补充语法中的非终结符。这意味着:
- 最初由 p 匹配的 token 序列会以 n 作为目标符号重新解析。如果 n 具有语法参数,则这些参数会被设置为 p 最初解析时使用的相同值。
- 如果该 token 序列能够被解析为 n 的单个实例且没有剩余 token,则:
- 我们将该 n 的实例(一个 Parse Node,对给定的 p 唯一)称为“由 p 覆盖的 n”。
- n 及其派生产生式的所有 Early Error 规则也适用于由 p 覆盖的 n。
- 否则(如果解析失败),它是一个早期 Syntax Error。
5.1.5 语法记号
5.1.5.1 终结符符号
在 ECMAScript 语法中,一些终结符符号以 fixed-width 字体显示。它们应完全按所写形式出现在源文本中。以这种方式指定的所有终结符符号码点,都应被理解为来自 Basic Latin 块的相应 Unicode 码点,而不是来自其他 Unicode 范围的任何外观相似码点。终结符符号中的码点不能用 \ UnicodeEscapeSequence 表示。
在终结符符号为单个 Unicode 码点的语法中(即词法、RegExp 和数值字符串语法),产生式中出现的多个连续定宽码点是一种简单简写,表示同样的码点序列,但写作独立的终结符符号。
例如,产生式:
HexIntegerLiteral ::
0x
HexDigits
是以下形式的简写:
HexIntegerLiteral ::
0
x
HexDigits
相比之下,在句法语法中,连续的一串定宽码点是单个终结符符号。
终结符符号还有另外两种形式:
5.1.5.2 非终结符符号和产生式
非终结符符号以斜体显示。非终结符的定义(也称为“产生式”)由被定义的非终结符名称引入,后跟一个或多个冒号。(冒号数量表示该产生式属于哪种语法。)随后的一行或多行给出该非终结符的一个或多个可选右手边。例如,句法定义:
WhileStatement :
while
(
Expression
)
Statement
说明非终结符 WhileStatement 表示 token while,后跟左圆括号 token,后跟 Expression,后跟右圆括号 token,后跟 Statement。Expression 和 Statement 的出现本身是非终结符。再举一个例子,句法定义:
ArgumentList :
AssignmentExpression
ArgumentList
,
AssignmentExpression
说明 ArgumentList 可以表示单个 AssignmentExpression,或表示 ArgumentList 后跟逗号再后跟 AssignmentExpression。该 ArgumentList 定义是递归的,也就是说,它以自身来定义自身。其结果是,ArgumentList 可以包含任意正数个实参,这些实参由逗号分隔,且每个实参表达式都是 AssignmentExpression。这种非终结符的递归定义很常见。
5.1.5.3 可选符号
下标后缀“opt”可能出现在终结符或非终结符之后,表示可选符号。包含可选符号的替代项实际上指定两个右手边,一个省略该可选元素,一个包含它。这意味着:
VariableDeclaration :
BindingIdentifier
Initializeropt
是以下形式的便捷缩写:
VariableDeclaration :
BindingIdentifier
BindingIdentifier
Initializer
并且:
ForStatement :
for
(
LexicalDeclaration
Expressionopt
;
Expressionopt
)
Statement
是以下形式的便捷缩写:
ForStatement :
for
(
LexicalDeclaration
;
Expressionopt
)
Statement
for
(
LexicalDeclaration
Expression
;
Expressionopt
)
Statement
而这又是以下形式的缩写:
ForStatement :
for
(
LexicalDeclaration
;
)
Statement
for
(
LexicalDeclaration
;
Expression
)
Statement
for
(
LexicalDeclaration
Expression
;
)
Statement
for
(
LexicalDeclaration
Expression
;
Expression
)
Statement
因此,在此示例中,非终结符 ForStatement 实际上有四个可选右手边。
5.1.5.4 语法参数
产生式可以通过形如“[parameters]”的下标注解进行参数化,该注解可作为后缀出现在产生式所定义的非终结符符号之后。“parameters”可以是单个名称,也可以是由逗号分隔的名称列表。参数化产生式是一组产生式的简写,这组产生式定义参数名的所有组合,并在参数化非终结符符号之后附加以前导下划线开头的参数名。这意味着:
StatementList[Return] :
ReturnStatement
ExpressionStatement
是以下形式的便捷缩写:
StatementList :
ReturnStatement
ExpressionStatement
StatementList_Return :
ReturnStatement
ExpressionStatement
并且:
StatementList[Return, In] :
ReturnStatement
ExpressionStatement
是以下形式的缩写:
StatementList :
ReturnStatement
ExpressionStatement
StatementList_Return :
ReturnStatement
ExpressionStatement
StatementList_In :
ReturnStatement
ExpressionStatement
StatementList_Return_In :
ReturnStatement
ExpressionStatement
多个参数会产生组合数量的产生式,其中并非所有产生式都一定会在完整语法中被引用。
产生式右手边对非终结符的引用也可以被参数化。例如:
StatementList :
ReturnStatement
ExpressionStatement[+In]
等价于说:
StatementList :
ReturnStatement
ExpressionStatement_In
并且:
StatementList :
ReturnStatement
ExpressionStatement[~In]
等价于:
StatementList :
ReturnStatement
ExpressionStatement
非终结符引用可以同时具有参数列表和“opt”后缀。例如:
VariableDeclaration :
BindingIdentifier
Initializer[+In]opt
是以下形式的缩写:
VariableDeclaration :
BindingIdentifier
BindingIdentifier
Initializer_In
在右手边非终结符引用上用“?”作为参数名前缀,会使该参数值取决于当前产生式左手边符号引用上是否出现该参数名。例如:
VariableDeclaration[In] :
BindingIdentifier
Initializer[?In]
是以下形式的缩写:
VariableDeclaration :
BindingIdentifier
Initializer
VariableDeclaration_In :
BindingIdentifier
Initializer_In
如果右手边替代项带有前缀“[+parameter]”,则只有在引用该产生式的非终结符符号时使用了该命名参数,该替代项才可用。如果右手边替代项带有前缀“[~parameter]”,则只有在引用该产生式的非终结符符号时未使用该命名参数,该替代项才可用。这意味着:
StatementList[Return] : [+Return]
ReturnStatement
ExpressionStatement
是以下形式的缩写:
StatementList :
ExpressionStatement
StatementList_Return :
ReturnStatement
ExpressionStatement
并且:
StatementList[Return] : [~Return]
ReturnStatement
ExpressionStatement
是以下形式的缩写:
StatementList :
ReturnStatement
ExpressionStatement
StatementList_Return :
ExpressionStatement
5.1.5.5 one of
当词语“one of”跟在语法定义的冒号之后时,它表示后续一行或多行上的每个终结符符号都是一个可选定义。例如,ECMAScript 的词法语法包含产生式:
NonZeroDigit :: one of 1 2 3 4 5 6 7 8 9
它只是以下形式的便捷缩写:
NonZeroDigit ::
1
2
3
4
5
6
7
8
9
5.1.5.6 [empty]
如果短语“[empty]”出现在产生式右手边,则表示该产生式的右手边不包含终结符或非终结符。
5.1.5.7 向前看限制
如果短语“[lookahead = seq]”出现在产生式右手边,则表示只有在 token 序列 seq 是紧接其后的输入 token 序列的前缀时,该产生式才可使用。类似地,“[lookahead ∈ set]”,其中 set 是 token 序列的有限非空集合,表示只有在 set 的某个元素是紧接其后的 token 序列的前缀时,该产生式才可使用。为方便起见,该集合也可以写作非终结符,此时它表示该非终结符可展开得到的所有 token 序列的集合。如果该非终结符可以展开为无限多个不同 token 序列,则认为这是编辑错误。
这些条件可以被否定。“[lookahead ≠ seq]”表示只有在 seq 不是紧接其后的输入 token 序列的前缀时,包含该条件的产生式才可使用;而“[lookahead ∉ set]”表示只有在 set 中没有元素是紧接其后的 token 序列的前缀时,该产生式才可使用。
作为示例,给定定义:
DecimalDigit :: one of 0 1 2 3 4 5 6 7 8 9
DecimalDigits ::
DecimalDigit
DecimalDigits
DecimalDigit
定义:
LookaheadExample ::
n
[lookahead ∉ { 1, 3, 5, 7, 9 }]
DecimalDigits
DecimalDigit
[lookahead ∉ DecimalDigit]
匹配字母 n 后跟一个或多个十进制数字且第一个数字为偶数,或者匹配一个后面不跟另一个十进制数字的十进制数字。
注意,当这些短语在句法语法中使用时,可能无法无歧义地识别紧接其后的 token 序列,因为确定后续 token 需要知道在后续位置使用哪个词法目标符号。因此,当这些短语在句法语法中使用时,如果 token 序列 seq 出现在向前看限制中(包括作为序列集合的一部分),而词法目标符号的选择可能改变 seq 是否会成为所得 token 序列的前缀,则认为这是编辑错误。
如果短语“[no LineTerminator here]”出现在句法语法产生式的右手边,则表示该产生式是受限产生式:如果 LineTerminator 出现在输入流中所示位置,则不能使用该产生式。例如,产生式:
ThrowStatement :
throw
[no LineTerminator here]
Expression
;
表示如果脚本中 throw token 与 Expression 之间出现 LineTerminator,则不能使用该产生式。
除非受限产生式禁止出现 LineTerminator,否则任意数量的 LineTerminator 都可以出现在输入元素流中任意两个连续 token 之间,而不影响脚本的句法可接受性。
5.1.5.9 but not
产生式右手边可以使用短语“but not”并随后指明要排除的展开,来指定某些展开不被允许。例如,产生式:
Identifier ::
IdentifierName but not ReservedWord
意味着非终结符 Identifier 可以被任何能够替换 IdentifierName 的码点序列替换,条件是同一码点序列不能替换 ReservedWord。
5.1.5.10 描述性短语
最后,在列出所有替代项不切实际的情况下,少数非终结符符号由无衬线字体的描述性短语描述:
SourceCharacter ::
any Unicode code point
5.2 算法约定
本规范经常使用编号列表来指定算法步骤。这些算法用于精确指定 ECMAScript 语言构造所要求的语义。这些算法并不意在暗示使用任何特定实现技术。在实践中,可能存在更高效的算法来实现给定特性。
算法可以用一个有序的、逗号分隔的别名名称序列显式参数化,这些别名可在算法步骤中用于引用对应位置传入的实参。可选参数用外层方括号表示([ , name ]),并且在算法步骤中与必需参数没有区别。rest 参数可以出现在参数列表末尾,以前导省略号表示(, ...name)。rest 参数将必需参数和可选参数之后提供的所有实参捕获到一个 List 中。如果没有这样的额外实参,该 List 为空。
算法步骤可以细分为顺序子步骤。子步骤会缩进,并且自身也可以进一步细分为缩进子步骤。大纲编号约定用于标识子步骤,第一层子步骤用小写字母标号,第二层子步骤用小写罗马数字标号。如果需要超过三层,则这些规则重复,第四层使用数字标号。例如:
- 顶层步骤
- 子步骤。
- 子步骤。
- 子子步骤。
- 子子子步骤
- 子子子子步骤
- 子子子子子步骤
步骤或子步骤可以写作一个“if”谓词,用其条件控制其子步骤。在这种情况下,只有在该谓词为真时才应用这些子步骤。如果步骤或子步骤以词语“else”开头,则它是同一层级前一个“if”谓词步骤的否定谓词。
步骤可以以“For each”或“Repeat”开头,以指定其子步骤的迭代应用。
以“Assert:”开头的步骤断言其算法的不变条件。这些断言用于明确本来会隐含的算法不变式。类似地,以“NOTE:”开头的步骤为附近步骤提供相关上下文。断言步骤和注记步骤严格而言是信息性的;它们不添加额外的语义要求,因此实现无需检查它们。
算法步骤可以使用形式“Let x be someValue”为任意值声明命名别名。这些别名类似引用,因为 x 和 someValue 都引用相同的底层数据,对任一者的修改对二者均可见。希望避免这种类引用行为的算法步骤应显式复制右手边:“Let x be a copy of someValue” 创建 someValue 的浅拷贝。
别名一经声明,就可以在任何后续步骤中引用,并且不得在声明之前的步骤中引用。别名可以使用形式“Set x to someOtherValue”进行修改。
5.2.1 求值顺序
当复杂表达式出现在算法步骤中时,应理解为按从左到右、从内到外的顺序求值。例如,步骤
- Return A(B(), C.[[D]]) + E(F()).
等价于
- Let tmp1 be B().
- Let tmp2 be C.[[D]].
- Let tmp3 be A(tmp1, tmp2).
- Let tmp4 be F().
- Let tmp5 be E(tmp4).
- Let tmp6 be tmp3 + tmp5.
- Return tmp6.
其中各种 tmpN 别名是临时的,并且只在这些步骤中可见。
5.2.2 抽象操作
为便于在本规范多个部分中使用,一些称为抽象操作的算法会被命名,并以参数化函数形式书写,从而可在其他算法中按名称引用。抽象操作通常使用函数应用风格来引用,例如 OperationName(arg1, arg2)。一些抽象操作被视为类似类的规范抽象的多态派发方法。这类类似方法的抽象操作通常使用方法应用风格引用,例如 someValue.OperationName(arg1, arg2)。
5.2.3 语法制导操作
语法制导操作是一个命名操作,其定义由算法组成,每个算法与某个 ECMAScript 语法中的一个或多个产生式关联。具有多个可选定义的产生式,通常会为每个替代项具有不同的算法。当算法与语法产生式关联时,它可以像引用算法参数一样引用该产生式替代项的终结符和非终结符符号。以这种方式使用时,非终结符符号指的是解析源文本时匹配到的实际替代定义。由某个语法产生式或由它派生出的 Parse Node 匹配的源文本,是从参与匹配的第一个终结符开始处到参与匹配的最后一个终结符结束处之间的那部分源文本。
当算法与产生式替代项关联时,该替代项通常显示时不带任何“[ ]”语法注解。此类注解只应影响对替代项的句法识别,而不影响该替代项的相关语义。
语法制导操作使用以下算法中步骤 1、3 和 4 上的约定,以 parse node 以及可选的其他参数来调用:
- Let status be SyntaxDirectedOperation of SomeNonTerminal.
- Let someParseNode be the parse of some source text.
- Perform SyntaxDirectedOperation of someParseNode.
- Perform SyntaxDirectedOperation of someParseNode with argument "value".
除非另有明确规定,否则所有链式产生式对可能应用于该产生式左手边非终结符的每个操作,都有一个隐式定义。该隐式定义只是用相同参数(若有)将同一操作重新应用于该链式产生式唯一的右手边非终结符,然后返回结果。例如,假设某算法具有形如“Return Evaluation of Block”的步骤,并且有一个产生式:
Block :
{
StatementList
}
但 Evaluation 操作没有与该产生式关联算法。在这种情况下,Evaluation 操作会隐式包含如下形式的关联:
Runtime Semantics: Evaluation
Block :
{
StatementList
}
- Return Evaluation of StatementList.
5.2.4 运行时语义
指定必须在运行时调用的语义的算法称为运行时语义。运行时语义由抽象操作或语法制导操作定义。
5.2.4.1 Completion ( completionRecord )
The abstract operation Completion takes argument completionRecord (a Completion Record) and returns a Completion Record. 它用于强调正在返回 Completion Record。 It performs the following steps when called:
- Assert: completionRecord is a Completion Record.
- Return completionRecord.
5.2.4.2 Throw
在算法步骤中,词语“throw”是返回调用 ThrowCompletion 的结果的简写。例如,
- If result.[[Error]] is not none, throw result.[[Error]].
等价于
- If result.[[Error]] is not none, return ThrowCompletion(result.[[Error]]).
要求抛出特定类型异常的算法步骤会构造要抛出的该类型异常。例如,
- Throw a TypeError exception.
等价于
- Return ThrowCompletion(a newly created TypeError object).
5.2.4.3 解包 Completion Records 的简写
前缀“?”和“!”用作解包 Completion Records 的简写。“?”用于将突然完成传播给调用方,或在其他情况下解包正常完成。“!”用于断言 Completion Record 是正常的并解包它。形式上,步骤
- Let result be ? record.
等价于
- Assert: record is a Completion Record.
- If record is an abrupt completion, return record.
- Let result be record.[[Value]].
同样,步骤
- Let result be ! record.
等价于
- Assert: record is a normal completion.
- Let result be record.[[Value]].
当“?”或“!”在任何其他上下文中使用时,首先应用 求值顺序 中给出的重写,直到可以应用本规则,然后应用本规则。例如,步骤
- Perform AO(? Other()).
可以重写为
- Let tmp1 be Other().
- Let tmp2 be ? tmp1.
- Perform AO(tmp2).
它又展开为
- Let tmp1 be Other().
- Assert: tmp1 is a Completion Record.
- If tmp1 is an abrupt completion, return tmp1.
- Let tmp2 be tmp1.[[Value]].
- Perform AO(tmp2).
5.2.4.4 隐式正常完成
在声明为返回 Completion Record 的抽象操作内的算法中,以及在所有内置函数内,返回值会首先传递给 NormalCompletion,并使用所得结果。本规则不适用于 Completion 算法内部,也不适用于该步骤中返回值已被清楚标记为 Completion Record 的情况;这些情况是:
如果从这类抽象操作中以任何其他方式返回 Completion Record,则这是编辑错误。例如,在这些抽象操作中,
- Return true.
与以下任一形式含义相同
- Return NormalCompletion(true).
或
- Let completion be NormalCompletion(true).
- Return Completion(completion).
或
- Return Completion Record { [[Type]]: normal, [[Value]]: true, [[Target]]: empty }.
注意,通过 ? 简写展开,以下示例是允许的,因为在展开后的步骤中,突然情况会直接返回应用 Completion 的结果,而正常情况会在解包之后发生隐式 NormalCompletion 应用。
- Return ? completion.
以下示例会是编辑错误,因为正在返回 Completion Record 而该步骤中未进行注解。
- Let completion be NormalCompletion(true).
- Return completion.
5.2.5 静态语义
上下文无关语法不足以表达所有规则,这些规则定义输入元素流是否形成可被求值的有效 ECMAScript Script 或 Module。在某些情况下,需要使用 ECMAScript 算法约定或散文式要求来表达的额外规则。这类规则总是与语法产生式关联,并称为该产生式的静态语义。
Static Semantic Rules 具有名称,并且通常使用算法定义。命名的 Static Semantic Rules 与语法产生式关联,而具有多个可选定义的产生式通常会为每个适用的命名静态语义规则的每个替代项具有不同算法。
一种特殊的静态语义规则是 Early Error Rule。Early error 规则定义与特定语法产生式关联的 early error 条件(参见条款 17)。大多数 early error 规则的求值不会在本规范的算法中显式调用。一致实现必须在首次求值 Script 或 Module 之前,验证用于解析该 Script 或 Module 的产生式的所有 early error 规则。如果违反任何 early error 规则,则该 Script 或 Module 无效且不能被求值。
5.2.6 数学操作
本规范引用以下种类的数值:
在本规范语言中,数值使用下标后缀来区分不同的数值种类。下标 𝔽 指 Numbers,下标 ℤ 指 BigInts。不带下标后缀的数值指数学值。本规范以 10 进制表示大多数数值;也使用形如 0x 后跟数字 0-9 或 A-F 的数值作为 16 进制值。
一般而言,当本规范引用一个数值时,例如在短语“the length of y”或“the integer represented by the four hexadecimal digits ...”中,如果未显式指定数值种类,该短语指数学值。引用 Number 或 BigInt 值的短语会显式标注;例如,“the Number value for the number of code points in …”或“the BigInt value for …”。
当术语 integer 在本规范中使用时,除非另有说明,它指的是属于整数集合的数学值。当术语 integral Number 在本规范中使用时,它指的是其数学值属于整数集合的有限 Number 值。
数值运算符如 +、×、= 和 ≥ 指由操作数类型决定的那些操作。当应用于数学值时,运算符指通常的数学操作。当应用于扩展数学值时,运算符指扩展实数上的通常数学操作;不定式未定义,其在本规范中的使用应被视为编辑错误。当应用于 Numbers 时,运算符指 IEEE 754-2019 中的相关操作。当应用于 BigInts 时,运算符指应用于该 BigInt 数学值的通常数学操作。应用于混合类型操作数(例如 Number 和数学值)的数值运算符未定义,并且在本规范中应被视为编辑错误。
数学值与 Numbers 或 BigInts 之间的转换在本文档中始终是显式的。从数学值或扩展数学值 x 到 Number 的转换表示为“the Number value for x”或 𝔽(x),并在 6.1.6.1 中定义。从整数 x 到 BigInt 的转换表示为“the BigInt value for x”或 ℤ(x)。从 Number 或 BigInt x 到数学值的转换表示为“the mathematical value of x”,或 ℝ(x)。+0𝔽 和 -0𝔽 的数学值是数学值 0。非有限值的数学值未定义。x 的 extended mathematical value of 是有限值时 x 的数学值,而对 +∞𝔽 和 -∞𝔽 分别为 +∞ 和 -∞;对 NaN 未定义。
数学函数 abs(x) 产生 x 的绝对值,如果 x < 0 则为 -x,否则为 x 自身。
数学函数 ln(x) 产生 x 的自然对数。数学函数 log10(x) 产生 x 的以 10 为底的对数。数学函数 log2(x) 产生 x 的以 2 为底的对数。
数学函数 min(x1, x2, … , xN) 产生 x1 到 xN 中数学上最小的值。数学函数 max(x1, x2, ..., xN) 产生 x1 到 xN 中数学上最大的值。这些数学函数的定义域和值域是扩展数学值。
记号“x modulo y”(y 必须为有限且非零)计算一个与 y 符号相同(或为零)的值 k,使得对于某个整数 q,有 abs(k) < abs(y) and x - k = q × y。
短语“the result of clamping x between lower and upper”(其中 x 是扩展数学值,lower 和 upper 是满足 lower ≤ upper 的数学值)在 x < lower 时产生 lower,在 x > upper 时产生 upper,否则产生 x。
数学函数 floor(x) 产生不大于 x 的最大整数(最接近 +∞)。
Note
floor(x) = x - (x modulo 1)。
数学函数 truncate(x) 通过向零舍入来移除 x 的小数部分,如果 x < 0 则产生 -floor(-x),否则产生 floor(x)。
数学函数 min、max、abs、floor 和 truncate 对 Numbers 和 BigInts 未定义,任何使用这些方法且带有非数学值实参的情况,在本规范中都会是编辑错误。
从下界 a 到上界 b 的区间,是一个可能无限、可能为空的同一数值类型的数值集合。每个边界会被描述为包含或排除其边界值,但不会同时如此。区间有以下四种:
- 从 a(包含)到 b(包含)的区间,也称为从 a 到 b 的闭区间,包含同一数值类型中满足 a ≤ x ≤ b 的所有值 x,且不包含其他值。
- 从 a(包含)到 b(排除)的区间,包含同一数值类型中满足 a ≤ x < b 的所有值 x,且不包含其他值。
- 从 a(排除)到 b(包含)的区间,包含同一数值类型中满足 a < x ≤ b 的所有值 x,且不包含其他值。
- 从 a(排除)到 b(排除)的区间,包含同一数值类型中满足 a < x < b 的所有值 x,且不包含其他值。
例如,从 1(包含)到 2(排除)的区间由 1 和 2 之间的所有数学值组成,包括 1 但不包括 2。为定义区间之目的,-0𝔽 < +0𝔽,因此,例如,下界为 +0𝔽 的闭区间包括 +0𝔽,但不包括 -0𝔽。NaN 永远不包含在区间中。
5.2.7 值记号
在本规范中,ECMAScript 语言值以 bold 显示。示例包括 null、true 或 "hello"。这些值与 ECMAScript 源文本相区分,例如 Function.prototype.apply 或 let n = 42;。
5.2.8 同一性
在本规范中,规范值和 ECMAScript 语言值都会进行相等比较。在进行相等比较时,值分为两类。无同一性的值在其所有固有特征都相同时,等于其他无同一性的值——例如整数的大小或序列的长度等特征。无同一性的值可以无需先前引用,而通过完整描述其特征来呈现。相比之下,每个有同一性的值都是唯一的,因此只等于它自身。有同一性的值类似于无同一性的值,但具有一个额外的不可猜测、不可改变、全局唯一的特征,称为同一性。对既有有同一性值的引用,不能仅通过描述它们来呈现,因为同一性本身无法描述;相反,对这些值的引用必须显式地从一个地方传递到另一个地方。一些有同一性的值是可变的,因此可以原地改变其特征(除其同一性外),使该值的所有持有者观察到新的特征。无同一性的值永远不等于有同一性的值。
从本规范的视角看,词语“is”用于比较两个值是否相等,如“If bool is true, then ...”;词语“contains”用于通过相等比较在列表中搜索某个值,如“If list contains a Record r such that r.[[Foo]] is true, then ...”。值的规范同一性决定这些比较的结果,并且在本规范中是公理性的。
从 ECMAScript 语言的视角看,语言值使用 SameValue 抽象操作及其传递调用的抽象操作进行相等比较。这些比较抽象操作的算法决定 ECMAScript 语言值的语言同一性。
对于规范值,无规范同一性的值示例包括但不限于:数学值和扩展数学值;ECMAScript 源文本、代理对、Directive Prologues 等;UTF-16 代码单元;Unicode 码点;枚举;抽象操作,包括语法制导操作、宿主钩子等;以及有序对。有规范同一性的规范值示例包括但不限于:任何种类的 Records,包括 Property Descriptors、PrivateElements 等;Parse Nodes;Lists;Sets 和 Relations;Abstract Closures;Data Blocks;Private Names;执行上下文和执行上下文栈;agent signifiers;以及 WaiterList Records。
除由 Symbol.for 产生的 Symbol 值外,所有 ECMAScript 语言值的规范同一性与语言同一性一致。无规范同一性且无语言同一性的 ECMAScript 语言值是 undefined、null、Booleans、Strings、Numbers 和 BigInts。有规范同一性和语言同一性的 ECMAScript 语言值是并非由 Symbol.for 产生的 Symbols 以及 Objects。由 Symbol.for 产生的 Symbol 值具有规范同一性,但没有语言同一性。