页面模式偏好

5 表示法约定

5.1 句法和词法文法

5.1.1 上下文无关文法

上下文无关文法由若干产生式组成。每个产生式的左侧是一个称为非终结符的抽象符号,其右侧是由零个或多个非终结符和终结符组成的序列。对于每种文法,终结符都取自指定的字母表。

链式产生式是右侧恰好包含一个非终结符以及零个或多个终结符的产生式。

从仅由一个称为目标符号的特定非终结符组成的句子开始,给定的上下文无关文法规定了一种语言,即通过反复将序列中的任意非终结符替换为以该非终结符为左侧的某个产生式的右侧,所能得到的所有可能终结符序列组成的集合(该集合可能无限)。

5.1.2 词法和 RegExp 文法

ECMAScript 的词法文法在 12 节中给出。该文法以符合 11.1 中 SourceCharacter 定义规则的 Unicode 码点作为终结符。它定义了一组从目标符号 InputElementDiv、InputElementTemplateTail、InputElementRegExp、InputElementRegExpOrTemplateTail 或 InputElementHashbangOrRegExp 开始的产生式,描述如何将这些码点的序列转换为输入元素序列。

除空白和注释之外的输入元素构成 ECMAScript 句法文法的终结符,称为 ECMAScript 词元。这些词元是 ECMAScript 语言的保留字、标识符、字面量和标点符号。此外,行终止符虽然不被视为词元,但也会成为输入元素流的一部分,并引导自动分号插入过程(12.10)。单纯的空白和单行注释会被丢弃,不会出现在句法文法的输入元素流中。MultiLineComment(即形式为 /*…*/ 的注释,无论是否跨越多行)如果不包含行终止符,同样会被直接丢弃;但如果 MultiLineComment 包含一个或多个行终止符,则会被替换为单个行终止符,成为句法文法输入元素流的一部分。

ECMAScript 的 RegExp 文法在 22.2.1 中给出。该文法同样以 SourceCharacter 所定义的码点作为终结符。它定义了一组从目标符号 Pattern 开始的产生式,描述如何将码点序列转换为正则表达式模式。

词法和 RegExp 文法的产生式使用两个冒号“::”作为分隔标点,以便区分。词法和 RegExp 文法共享某些产生式。

5.1.3 数值字符串文法

数值字符串文法见 7.1.4.1。它以 SourceCharacter 为终结符,用于从目标符号 StringNumericLiteral 开始将 String 值转换为数值(它与数值字面量的词法文法相似但不同)。

数值字符串文法的产生式使用三个冒号“:::”作为标点,以便区分,并且从不用于解析源文本。

5.1.4 句法文法

ECMAScript 的句法文法在 13 至 16 节中给出。该文法以词法文法定义的 ECMAScript 词元作为终结符(5.1.2)。它定义了一组从两个可选目标符号 Script 和 Module 开始的产生式,描述词元序列如何构成 ECMAScript 程序中句法正确的独立组成部分。

当要将码点流解析为 ECMAScript Script 或 Module 时,首先通过反复应用词法文法将其转换为输入元素流;然后对该输入元素流应用一次句法文法进行解析。如果输入元素流中的词元无法被解析为目标非终结符(Script 或 Module)的单个实例且不留下任何词元,则该输入流存在句法错误。

解析成功时,会构造一棵解析树,这是一种有根树结构,其中每个节点都是解析节点。每个解析节点都是文法中某个符号的实例;它表示可由该符号推导出的源文本片段。解析树的根节点表示整个源文本,是此次解析的目标符号的实例。当解析节点是某个非终结符的实例时,它也是以该非终结符为左侧的某个产生式的实例。此外,它具有零个或多个子节点,分别对应产生式右侧的每个符号:每个子节点都是相应符号的实例,即解析节点。

每次调用解析器都会实例化新的解析节点,即使源文本相同,也不会在不同解析之间复用解析节点。当且仅当解析节点表示同一源文本片段、是同一文法符号的实例,并且由同一次解析器调用产生时,才将它们视为同一解析节点。

注 1

多次解析同一个 String 值会产生不同的解析节点。例如,考虑:

let str = "1 + 1;";
eval(str);
eval(str);

每次调用 eval 都会将 str 的值转换为 ECMAScript 源文本,并执行独立的解析,创建各自独立的解析节点树。即使每次解析所处理的源文本都来自同一个 String 值,这些树仍然不同。

注 2
解析节点是规范中的概念性构造,不要求实现使用类似的数据结构。

句法文法的产生式仅使用一个冒号“:”作为标点,以便区分。

13 至 16 节给出的句法文法,并未完整说明哪些词元序列可被接受为正确的 ECMAScript Script 或 Module。某些额外的词元序列也会被接受,即只需在序列中的某些位置(例如行终止符字符之前)添加分号,就能由文法描述的序列。此外,如果行终止符字符出现在某些“不合适”的位置,即使某些词元序列由文法描述,也不被认为是可接受的。

在某些情况下,为避免歧义,句法文法使用更一般化的产生式,允许不能构成有效 ECMAScript Script 或 Module 的词元序列。例如,对象字面量和对象解构模式就使用了这种技术。在这种情况下,会提供限制更严格的补充文法,进一步限制可接受的词元序列。通常,随后会有一条提前错误规则规定,在某些上下文中,“p 必须覆盖一个 n”,其中 p 是解析节点(一般化产生式的实例),而 n 是补充文法中的非终结符。这意味着:

  1. 不对 p 或其任何后代节点应用提前错误规则。
  2. 以 n 为目标符号,重新解析最初由 p 匹配的词元序列。如果 n 接受文法参数,则将它们设置为最初解析 p 时使用的相同值。
  3. 如果该词元序列能够被解析为 n 的单个实例,且没有剩余词元,则:
    1. 我们将 n 的该实例(对于给定 p 唯一的解析节点)称为“由 p 覆盖的 n”。
    2. 对由 p 覆盖的 n 及其后代节点应用提前错误规则,并根据进一步出现的“必须覆盖”情况进行调整。
  4. 否则(如果解析失败),这是一个提前句法错误。

5.1.5 文法表示法

5.1.5.1 终结符

在 ECMAScript 文法中,某些终结符以等宽字体显示。它们必须按所写形式原样出现在源文本中。以这种方式指定的所有终结符码点都应理解为基本拉丁字母区块中的相应 Unicode 码点,而不是其他 Unicode 范围中外观相似的码点。终结符中的码点不能通过 \ UnicodeEscapeSequence 表示。

在以单个 Unicode 码点作为终结符的文法(即词法、RegExp 和数值字符串文法)中,产生式中连续出现的多个等宽码点,只是将相同码点序列写成独立终结符时的一种简写。

例如,产生式:

HexIntegerLiteral :: 0x HexDigits

是以下形式的简写:

HexIntegerLiteral :: 0 x HexDigits

相比之下,在句法文法中,一串连续的等宽码点表示单个终结符。

终结符还有另外两种形式:

  • 在词法和 RegExp 文法中,没有常规打印表示形式的 Unicode 码点改用“<ABBREV>”形式表示,其中“ABBREV”是该码点或码点集合的助记符。这些形式在 Unicode 格式控制字符、空白 和 行终止符 中定义。
  • 在句法文法中,某些终结符(例如 IdentifierName 和 RegularExpressionLiteral)以斜体显示,因为它们引用词法文法中的同名非终结符。

5.1.5.2 非终结符和产生式

非终结符以斜体显示。非终结符的定义(也称为“产生式”)以所定义的非终结符名称开头,后跟一个或多个冒号。(冒号的数量表示该产生式属于哪种文法。)随后各行列出该非终结符的一个或多个可选右侧。例如,句法定义:

WhileStatement : while ( Expression ) Statement

表明非终结符 WhileStatement 表示词元 while,后跟左括号词元,再跟一个 Expression,再跟右括号词元,最后跟一个 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 的词法文法包含以下产生式:

BinaryDigit :: one of 0 1

它只是以下形式的便捷简写:

BinaryDigit :: 0 1

5.1.5.6 [empty]

如果短语“[empty]”作为产生式的右侧出现,则表示该产生式的右侧不包含任何终结符或非终结符。

5.1.5.7 前瞻限制

如果短语“[lookahead = seq]”出现在产生式的右侧,则表示仅当词元序列 seq 是紧随其后的输入词元序列的前缀时,才可以使用该产生式。类似地,“[lookahead ∈ set]”(其中 set 是词元序列的有限非空集合)表示仅当 set 的某个元素是紧随其后的词元序列的前缀时,才可以使用该产生式。为方便起见,该集合也可以写成非终结符,在这种情况下,它表示该非终结符能够展开为的所有词元序列的集合。如果该非终结符能够展开为无限多个不同的词元序列,则视为编辑错误。

这些条件可以取反。“[lookahead ≠ seq]”表示仅当 seq 不是紧随其后的输入词元序列的前缀时,才可以使用包含它的产生式;“[lookahead ∉ set]”表示仅当 set 中没有任何元素是紧随其后的词元序列的前缀时,才可以使用该产生式。

例如,给定以下定义:

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 后跟一个或多个十进制数字且第一个数字为偶数的序列,或者匹配一个后面没有其他十进制数字的十进制数字。

注意,当这些短语用于句法文法时,可能无法明确确定紧随其后的词元序列,因为确定后续词元需要知道在后续位置应使用哪个词法目标符号。因此,当这些短语用于句法文法时,如果所选词法目标符号可能改变 seq 是否为生成的词元序列的前缀,那么让词元序列 seq 出现在前瞻限制中(包括作为序列集合的一部分)就被视为编辑错误。

5.1.5.8 [no LineTerminator here]

如果短语“[no LineTerminator here]”出现在句法文法某个产生式的右侧,则表示该产生式是受限产生式:如果输入流的指定位置出现 LineTerminator,就不得使用该产生式。例如,产生式:

ThrowStatement : throw [no LineTerminator here] Expression ;

表示如果脚本中的 throw 词元与 Expression 之间出现 LineTerminator,就不得使用该产生式。

除非受限产生式禁止出现 LineTerminator,否则输入元素流中任意两个连续词元之间都可以出现任意数量的 LineTerminator,而不影响脚本在句法上的可接受性。

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 ])表示,在算法步骤中与必需形参没有区别。剩余形参可以出现在形参列表末尾,使用前置省略号(, ...name)表示。剩余形参将必需形参和可选形参之后提供的所有实参收集到一个列表中。如果没有这样的额外实参,该列表为空。

算法步骤可以细分为顺序执行的子步骤。子步骤使用缩进,并且自身可以进一步细分为缩进的子步骤。子步骤使用大纲编号约定标识,第一级子步骤以小写字母标记,第二级子步骤以小写罗马数字标记。如果需要超过三级,则重复这些规则,第四级使用数字标记。例如:

  1. 顶层步骤
    1. 子步骤。
    2. 子步骤。
      1. 二级子步骤。
        1. 三级子步骤
          1. 四级子步骤
            1. 五级子步骤

步骤或子步骤可以写成“如果”谓词,以对其子步骤的执行设置条件。在这种情况下,仅当谓词为真时才执行子步骤。如果步骤或子步骤以“否则”开头,则它是对同一级前一个“如果”谓词步骤的否定。

步骤可以以“对于每个”或“重复”开头,以规定迭代执行其子步骤。

以“断言:”开头的步骤断言其算法中的某个不变条件。这些断言用于显式说明原本隐含的算法不变条件。类似地,以“注:”开头的步骤为附近步骤提供相关上下文。断言步骤和注释步骤完全属于说明性内容;它们不增加任何语义要求,因此实现无需检查它们。

算法步骤可以使用“令 x 为 someValue”的形式为任何值声明具名别名。这些别名类似于引用,因为 x 和 someValue 都指向同一底层数据,对任意一方的修改对双方都可见。希望避免这种类似引用行为的算法步骤应显式复制右侧的值:“令 x 为 someValue 的副本”会创建 someValue 的浅拷贝。

别名一经声明,就可以在后续任何步骤中引用,但不得在声明之前的步骤中引用。可以使用“将 x 设置为 someOtherValue”的形式修改别名。

5.2.1 求值顺序

当算法步骤中出现复杂表达式时,应理解为按从左到右、从内到外的顺序求值。例如,步骤

  1. 返回 A(B(), C.[[D]]) + E(F())。

等价于

  1. 令 tmp1 为 B()。
  2. 令 tmp2 为 C.[[D]]。
  3. 令 tmp3 为 A(tmp1, tmp2)。
  4. 令 tmp4 为 F()。
  5. 令 tmp5 为 E(tmp4)。
  6. 令 tmp6 为 tmp3 + tmp5。
  7. 返回 tmp6。

其中,各个 tmpN 别名都是临时的,仅在这些步骤中可见。

5.2.2 抽象操作

为了便于在本规范的多个部分中使用,某些称为抽象操作的算法会被命名,并以参数化函数形式书写,从而可以在其他算法中通过名称引用。抽象操作通常使用类似 OperationName(arg1, arg2) 的函数调用形式引用。某些抽象操作被视为类式规范抽象中以多态方式分派的方法。这些类似方法的抽象操作通常使用类似 someValue.OperationName(arg1, arg2) 的方法调用形式引用。

5.2.3 语法制导操作

语法制导操作是一种具名操作,其定义由多个算法组成,每个算法都与某种 ECMAScript 文法中的一个或多个产生式相关联。具有多个可选定义的产生式通常会为每个候选项关联不同的算法。当算法与文法产生式相关联时,它可以引用该产生式候选项中的终结符和非终结符,就像它们是算法的参数一样。以这种方式使用时,非终结符指的是解析源文本时实际匹配的可选定义。文法产生式或由其派生的解析节点所匹配的源文本,是从参与匹配的第一个终结符的起始位置开始,到参与匹配的最后一个终结符的结束位置为止的源文本部分。

当算法与产生式的某个候选项相关联时,该候选项通常不带任何“[ ]”文法注记。这些注记只应影响候选项的句法识别,而不影响与该候选项关联的语义。

使用以下算法中步骤 1、3 和 4 所示的约定,可以用解析节点以及可选的其他参数调用语法制导操作:

  1. 令 status 为 SomeNonTerminal 的 SyntaxDirectedOperation。
  2. 令 someParseNode 为某段源文本的解析结果。
  3. 执行 someParseNode 的 SyntaxDirectedOperation。
  4. 以 "value" 为参数执行 someParseNode 的 SyntaxDirectedOperation。

除非另有明确规定,所有链式产生式都为可能应用于其左侧非终结符的每个操作提供隐式定义。隐式定义只是使用相同参数(如果有),将相同操作重新应用于链式产生式右侧唯一的非终结符,然后返回结果。例如,假设某个算法包含形式为“返回 Block 的 Evaluation”的步骤,并且存在以下产生式:

Block : { StatementList }

但 Evaluation 操作没有为该产生式关联算法。在这种情况下,Evaluation 操作隐式包含以下形式的关联:

Runtime Semantics: Evaluation

Block : { StatementList }
  1. 返回 StatementList 的 Evaluation。

5.2.4 运行时语义

规定必须在运行时调用的语义的算法称为运行时语义。运行时语义由抽象操作或语法制导操作定义。

5.2.4.1 Completion ( completionRecord )

抽象操作 Completion,接收参数 completionRecord (完成记录);返回值:完成记录。 它用于强调正在返回一个完成记录。 调用时执行以下步骤:

  1. 断言:completionRecord 是一个完成记录。
  2. 返回 completionRecord。

5.2.4.2 抛出

在算法步骤中,“抛出”是返回调用 ThrowCompletion 所得结果的简写。例如,

  1. 如果 result.[[Error]] 不是 none,则抛出 result.[[Error]]。

等价于

  1. 如果 result.[[Error]] 不是 none,则返回 ThrowCompletion(result.[[Error]])。

要求抛出特定类型异常的算法步骤会构造该类型的异常以供抛出。例如,

  1. 抛出一个 TypeError 异常。

等价于

  1. 返回 ThrowCompletion(一个新创建的 TypeError 对象)。

5.2.4.3 解包完成记录的简写

前缀“?”和“!”用作解包完成记录的简写。“?”用于将突然完成传播给调用者,或者在其他情况下解包正常完成。“!”用于断言完成记录是正常完成并将其解包。形式上,步骤

  1. 令 result 为 ? record。

等价于

  1. 断言:record 是一个完成记录。
  2. 如果 record 是突然完成,则返回 record。
  3. 令 result 为 record.[[Value]]。

类似地,步骤

  1. 令 result 为 ! record。

等价于

  1. 断言:record 是正常完成。
  2. 令 result 为 record.[[Value]]。

当“?”或“!”用于任何其他上下文时,先应用 求值顺序 中给出的改写,直到可以应用此规则,然后应用此规则。例如,步骤

  1. 执行 AO(? Other())。

可以改写为

  1. 令 tmp1 为 Other()。
  2. 令 tmp2 为 ? tmp1。
  3. 执行 AO(tmp2)。

随后又可展开为

  1. 令 tmp1 为 Other()。
  2. 断言:tmp1 是一个完成记录。
  3. 如果 tmp1 是突然完成,则返回 tmp1。
  4. 令 tmp2 为 tmp1.[[Value]]。
  5. 执行 AO(tmp2)。

5.2.4.4 隐式正常完成

在声明返回完成记录的抽象操作的算法中,以及所有内置函数中,返回的值会先传递给 NormalCompletion,然后改用所得结果。此规则不适用于 Completion 算法内部,也不适用于在该步骤中明确将所返回的值标记为完成记录的情况;这些情况包括:

如果通过任何其他方式从此类抽象操作返回完成记录,则属于编辑错误。例如,在这些抽象操作中,

  1. 返回 true。

与以下任一种形式具有相同含义

  1. 返回 NormalCompletion(true)。

或

  1. 令 completion 为 NormalCompletion(true)。
  2. 返回 Completion(completion)。

或

  1. 返回完成记录 { [[Type]]: normal, [[Value]]: true, [[Target]]: empty }。

注意,通过展开 ? 简写,以下示例是允许的,因为在展开后的步骤中,突然完成的情况下会直接返回应用 Completion 所得的结果,而正常完成的情况下会在解包之后隐式应用 NormalCompletion。

  1. 返回 ? completion。

以下示例属于编辑错误,因为该步骤返回了完成记录,却没有在该步骤中标明这一点。

  1. 令 completion 为 NormalCompletion(true)。
  2. 返回 completion。

5.2.5 静态语义

上下文无关文法的表达能力不足以表达所有用于确定输入元素流是否构成可求值的有效 ECMAScript Script 或 Module 的规则。在某些情况下,需要额外的规则,这些规则可以使用 ECMAScript 算法约定或文字要求来表达。此类规则始终与文法的某个产生式关联,称为该产生式的静态语义。

静态语义规则具有名称,通常使用算法定义。具名静态语义规则与文法产生式关联,对于具有多个可选定义的产生式,其每个候选项通常都会为每个适用的具名静态语义规则提供一个不同的算法。

一种特殊的静态语义规则是提前错误规则。提前错误规则定义与特定文法产生式关联的提前错误条件(参见 17 节)。本规范的算法不会显式调用大多数提前错误规则的求值。符合规范的实现必须在首次对 Script 或 Module 求值之前,验证用于解析该 Script 或 Module 的产生式的所有提前错误规则。如果违反任何提前错误规则,则该 Script 或 Module 无效,不能求值。

5.2.6 数学运算

本规范引用以下种类的数值:

在本规范的语言中,数值通过下标后缀在不同的数值种类之间加以区分。下标 𝔽 表示 Number,下标 ℤ 表示 BigInt。没有下标后缀的数值表示数学值。本规范中的大多数数值采用十进制表示;它还使用由 0x 后跟数字 0-9 或 A-F 形式组成的数值来表示十六进制值。

一般而言,当本规范引用某个数值时,例如短语“y 的长度”或“四个十六进制数字表示的整数……”,如果没有显式指定数值种类,则该短语表示数学值。引用 Number 或 BigInt 值的短语会显式注明;例如,“……中的码点数量对应的 Number 值”或“……对应的 BigInt 值”。

当本规范使用术语整数时,除非另有说明,它表示属于整数集合的数学值。当本规范使用术语整数 Number时,它表示其数学值属于整数集合的有限 Number 值。

诸如 +、×、= 和 ≥ 之类的数值运算符,根据操作数的类型表示相应的运算。当应用于数学值时,这些运算符表示通常的数学运算。当应用于扩展数学值时,这些运算符表示扩展实数上的通常数学运算;未定式未定义,在本规范中使用未定式应被视为编辑错误。当应用于 Number 时,这些运算符表示 IEEE 754-2019 中相应的运算。当应用于 BigInt 时,这些运算符表示应用于该 BigInt 数学值的通常数学运算。应用于混合类型操作数(例如一个 Number 和一个数学值)的数值运算符未定义,应被视为本规范中的编辑错误。

本文件中,数学值与 Number 或 BigInt 之间的转换始终是显式的。从数学值或扩展数学值 x 到 Number 的转换表示为“x 对应的 Number 值”或 𝔽(x),并在 6.1.6.1 中定义。从整数 x 到 BigInt 的转换表示为“x 对应的 BigInt 值”或 ℤ(x)。从 Number 或 BigInt x 到数学值的转换表示为“x 的数学值”,或 ℝ(x)。+0𝔽 和 -0𝔽 的数学值是数学值 0。非有限值的数学值未定义。x 的扩展数学值对于有限值是 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。

短语“将 x 限制在 lower 和 upper 之间的结果”(其中 x 是扩展数学值,lower 和 upper 是满足 lower ≤ upper 的数学值)在 x < lower 时产生 lower,在 x > upper 时产生 upper,否则产生 x。

数学函数 floor(x) 产生不大于 x 的最大整数(最接近 +∞)。

注

floor(x) = x - (x modulo 1)。

数学函数 truncate(x) 通过向零舍入来移除 x 的小数部分;如果 x < 0,则产生 -floor(-x),否则产生 floor(x)。

数学函数 min、max、abs、floor 和 truncate 未针对 Number 和 BigInt 定义,任何以非数学值作为参数使用这些方法的情况都属于本规范中的编辑错误。

从下界 a 到上界 b 的区间是由相同数值类型的数值构成的集合,该集合可能是无限的,也可能为空。每个边界都将被描述为包含或不包含,但不会同时为两者。区间有以下四种:

例如,从 1(包含)到 2(不包含)的区间由 1 和 2 之间的所有数学值组成,其中包含 1,但不包含 2。为了定义区间,-0𝔽 < +0𝔽,因此,例如,下界为 +0𝔽 的闭区间包含 +0𝔽,但不包含 -0𝔽。NaN 永远不会包含在区间中。

5.2.7 值的表示法

在本规范中,ECMAScript 语言值以粗体显示。例如 null、true 或 "hello"。它们与 Function.prototype.apply 或 let n = 42; 等 ECMAScript 源文本相区别。

5.2.8 标识

在本规范中,规范值和 ECMAScript 语言值都可以进行相等性比较。进行相等性比较时,值分为两类。如果所有固有特征都相同,例如整数的大小或序列的长度,则无标识的值与其他无标识的值相等。无需事先持有引用,只要完整描述无标识的值的特征,就可以给出该值。相比之下,每个有标识的值都是唯一的,因此仅与自身相等。有标识的值类似于无标识的值,但额外具有一个不可猜测、不可更改、全局唯一的特征,称为标识。由于标识本身无法描述,因此仅通过描述无法给出对现有有标识的值的引用;相反,必须将对这些值的引用从一个位置显式传递到另一个位置。某些有标识的值是可变的,因此可以原地更改其特征(标识除外),使该值的所有持有者都观察到新的特征。无标识的值永远不等于有标识的值。

从本规范的角度看,“是”用于比较两个值是否相等,例如“如果 bool 是 true,则 ...”;“包含”用于通过相等性比较在列表中查找值,例如“如果 list 包含一个记录 r,且 r.[[Foo]] 是 true,则 ...”。值的规范标识决定这些比较的结果,并在本规范中被视为公理性的概念。

从 ECMAScript 语言的角度看,语言值通过 SameValue 抽象操作及其传递调用的抽象操作进行相等性比较。这些比较抽象操作的算法决定 ECMAScript 语言值的语言标识。

对于规范值,没有规范标识的值的示例包括但不限于:数学值和扩展数学值;ECMAScript 源文本、代理对、指令序言等;UTF-16 码元;Unicode 码点;枚举值;抽象操作,包括语法制导操作、宿主钩子等;以及有序对。具有规范标识的规范值的示例包括但不限于:任何种类的记录,包括属性描述符、PrivateElement 等;解析节点;列表;集合和关系;抽象闭包;数据块;私有名称;执行上下文和执行上下文栈;代理标识符;以及 WaiterList 记录。

除 Symbol.for 产生的 Symbol 值之外,所有 ECMAScript 语言值的规范标识都与语言标识一致。既没有规范标识也没有语言标识的 ECMAScript 语言值包括 undefined、null、Boolean 值、String 值、Number 值和 BigInt 值。同时具有规范标识和语言标识的 ECMAScript 语言值包括非 Symbol.for 产生的 Symbol 值和对象。Symbol.for 产生的 Symbol 值具有规范标识,但没有语言标识。