12 ECMAScript 语言:词法语法 (ECMAScript Language: Lexical Grammar)

ECMAScript ScriptModule 的源码文本首先被转换为输入元素序列,这些输入元素包括记号 (token)、行终止符、注释或空白。源码从左到右扫描,反复取能形成下一个输入元素的最长可能码点序列。

在若干情形下,词法输入元素的识别会对消费这些输入元素的句法语法上下文敏感,因此词法语法需要多个目标符号InputElementHashbangOrRegExp 目标用于 ScriptModule 的开始处。InputElementRegExpOrTemplateTail 目标用于允许出现 RegularExpressionLiteralTemplateMiddleTemplateTail 的句法语境。InputElementRegExp 目标符号用于所有允许 RegularExpressionLiteral 但不允许 TemplateMiddleTemplateTail 的句法语境。InputElementTemplateTail 目标用于所有允许 TemplateMiddleTemplateTail 但不允许 RegularExpressionLiteral 的句法语境。所有其它语境中,使用 InputElementDiv 作为词法目标符号

Note

使用多个词法目标可确保不存在会影响自动分号插入的词法二义性。例如,没有任何句法语境同时允许以除法或除法赋值开头以及以 RegularExpressionLiteral 开头。这一点不受分号插入影响(见 12.10);在如下示例中:

a = b
/hi/g.exec(c).map(d);

当一个 LineTerminator 之后第一个非空白、非注释码点为 U+002F (SOLIDUS),且句法上下文允许除法或除法赋值时,不会在该 LineTerminator 处插入分号。也就是说,上例被解释为与下列代码相同:

a = b / hi / g.exec(c).map(d);

Syntax

InputElementDiv :: WhiteSpace LineTerminator Comment CommonToken DivPunctuator RightBracePunctuator InputElementRegExp :: WhiteSpace LineTerminator Comment CommonToken RightBracePunctuator RegularExpressionLiteral InputElementRegExpOrTemplateTail :: WhiteSpace LineTerminator Comment CommonToken RegularExpressionLiteral TemplateSubstitutionTail InputElementTemplateTail :: WhiteSpace LineTerminator Comment CommonToken DivPunctuator TemplateSubstitutionTail InputElementHashbangOrRegExp :: WhiteSpace LineTerminator Comment CommonToken HashbangComment RegularExpressionLiteral

12.1 Unicode 格式控制字符 (Unicode Format-Control Characters)

Unicode 格式控制字符(即 Unicode 字符数据库中类别 “Cf” 的字符,例如 LEFT-TO-RIGHT MARK 或 RIGHT-TO-LEFT MARK)是用于在缺乏更高层协议(如标记语言)时控制一段文本排版的控制码。

允许在源码文本中使用格式控制字符有助于编辑与显示。所有格式控制字符可出现在注释中,以及字符串字面量、模板字面量和正则表达式字面量中。

U+FEFF (ZERO WIDTH NO-BREAK SPACE) 是一种主要用于文本开头以标记其为 Unicode 并允许检测编码与字节序的格式控制字符。用于该目的的 <ZWNBSP> 字符有时也可能在文本开头之后出现,例如连接文件的结果。在 ECMAScript 源码文本中,除注释、字符串字面量、模板字面量和正则表达式字面量外,<ZWNBSP> 码点被视为空白字符(见 12.2)。

12.2 空白 (White Space)

空白码点用于提升源码可读性并分隔记号(不可再分的词法单元),除此之外没有意义。空白码点可出现在任意两个记号之间以及输入开头或结尾。空白码点可出现在 StringLiteralRegularExpressionLiteralTemplateTemplateSubstitutionTail 内部,此时它们是字面量值组成部分的有效码点;也可出现在 Comment 内,但不能出现在其它类型的记号内部。

ECMAScript 的空白码点列于 Table 33

Table 33: 空白码点 (White Space Code Points)
Code Points 名称 (Name) 缩写 (Abbreviation)
U+0009 CHARACTER TABULATION <TAB>
U+000B LINE TABULATION <VT>
U+000C FORM FEED (FF) <FF>
U+FEFF ZERO WIDTH NO-BREAK SPACE <ZWNBSP>
any code point in general category “Space_Separator” <USP>
Note 1

U+0020 (SPACE) 与 U+00A0 (NO-BREAK SPACE) 码点属于 <USP>。

Note 2

Table 33 所列码点外,ECMAScript WhiteSpace 有意排除所有具有 Unicode “White_Space” 属性但不属于一般类别 “Space_Separator”(“Zs”) 的码点。

Syntax

WhiteSpace :: <TAB> <VT> <FF> <ZWNBSP> <USP>

12.3 行终止符 (Line Terminators)

与空白码点类似,行终止符码点用于提升源码可读性并分隔记号。但与空白码点不同,行终止符会对句法语法行为产生影响。一般而言,行终止符可出现在任意两个记号之间,但也有少数位置为句法语法所禁止。行终止符还影响自动分号插入过程(见 12.10)。行终止符不能出现在除 StringLiteralTemplateTemplateSubstitutionTail 之外的任何记号内部。<LF> 与 <CR> 行终止符除作为 LineContinuation 的一部分外,不能出现在 StringLiteral 记号内。

MultiLineComment 内可以出现行终止符,但 SingleLineComment 内不能。

行终止符包含在正则表达式 \s 类所匹配的空白码点集合中。

ECMAScript 行终止符码点列于 Table 34

Table 34: 行终止符码点 (Line Terminator Code Points)
Code Point Unicode 名称 (Unicode Name) 缩写 (Abbreviation)
U+000A LINE FEED (LF) <LF>
U+000D CARRIAGE RETURN (CR) <CR>
U+2028 LINE SEPARATOR <LS>
U+2029 PARAGRAPH SEPARATOR <PS>

只有 Table 34 中的 Unicode 码点被视为行终止符。其它换行或断行的 Unicode 码点不会被视为行终止符,但若满足 Table 33 所列要求,则被视为空白。序列 <CR><LF> 常用作行终止符;在报告行号时应将其视为单个 SourceCharacter

Syntax

LineTerminator :: <LF> <CR> <LS> <PS> LineTerminatorSequence :: <LF> <CR> [lookahead ≠ <LF>] <LS> <PS> <CR> <LF>

12.4 注释 (Comments)

注释可以是单行或多行。多行注释不能嵌套。

由于单行注释可包含除 LineTerminator 码点外的任意 Unicode 码点,并且根据“一段记号总是尽可能长”的通则,单行注释总是从 // 标记到该行末端的全部码点。然而,行末的 LineTerminator 不视为单行注释的一部分;它被词法语法单独识别并进入供句法语法使用的输入元素流。这一点很重要,因为这意味着单行注释的有无不影响自动分号插入(见 12.10)。

注释的行为类似空白并被丢弃;但若 MultiLineComment 含有行终止符码点,则整个注释在句法解析目的上被视为一个 LineTerminator

Syntax

Comment :: MultiLineComment SingleLineComment MultiLineComment :: /* MultiLineCommentCharsopt */ MultiLineCommentChars :: MultiLineNotAsteriskChar MultiLineCommentCharsopt * PostAsteriskCommentCharsopt PostAsteriskCommentChars :: MultiLineNotForwardSlashOrAsteriskChar MultiLineCommentCharsopt * PostAsteriskCommentCharsopt MultiLineNotAsteriskChar :: SourceCharacter but not * MultiLineNotForwardSlashOrAsteriskChar :: SourceCharacter but not one of / or * SingleLineComment :: // SingleLineCommentCharsopt SingleLineCommentChars :: SingleLineCommentChar SingleLineCommentCharsopt SingleLineCommentChar :: SourceCharacter but not LineTerminator

本节若干产生式在 B.1.1 中给出替代定义。

12.5 Hashbang 注释 (Hashbang Comments)

Hashbang 注释对位置敏感,并且与其它类型注释一样从句法语法的输入元素流中被丢弃。

Syntax

HashbangComment :: #! SingleLineCommentCharsopt

12.6 记号 (Tokens)

Syntax

CommonToken :: IdentifierName PrivateIdentifier Punctuator NumericLiteral StringLiteral Template Note

DivPunctuatorRegularExpressionLiteralRightBracePunctuatorTemplateSubstitutionTail 产生式派生的额外记号未包含在 CommonToken 中。

12.7 名称与关键字 (Names and Keywords)

IdentifierNameReservedWord 是按 Unicode 标准附件 #31《标识符与模式语法》中“默认标识符语法”解释的记号,并带有少量修改。ReservedWordIdentifierName枚举子集。句法语法将 Identifier 定义为不是 ReservedWordIdentifierName。Unicode 标识符语法基于 Unicode 标准规定的字符属性。符合规范的 ECMAScript 实现必须将 Unicode 标准最新版本中指定类别的码点视为属于这些类别。实现可以识别 Unicode 后续版本定义的标识符码点。

Note 1

本标准特别增加:U+0024 (DOLLAR SIGN) 与 U+005F (LOW LINE) 可在 IdentifierName 任意位置使用。

Syntax

PrivateIdentifier :: # IdentifierName IdentifierName :: IdentifierStart IdentifierName IdentifierPart IdentifierStart :: IdentifierStartChar \ UnicodeEscapeSequence IdentifierPart :: IdentifierPartChar \ UnicodeEscapeSequence IdentifierStartChar :: UnicodeIDStart $ _ IdentifierPartChar :: UnicodeIDContinue $ AsciiLetter :: one of a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z UnicodeIDStart :: any Unicode code point with the Unicode property “ID_Start” UnicodeIDContinue :: any Unicode code point with the Unicode property “ID_Continue”

非终结符 UnicodeEscapeSequence 的定义见 12.9.4

Note 2

非终结符 IdentifierPart 通过 UnicodeIDContinue 派生 _

Note 3

具有 Unicode 属性 “ID_Start” 与 “ID_Continue” 的码点集合分别包含具有 “Other_ID_Start” 与 “Other_ID_Continue” 属性的码点。

12.7.1 标识符名称 (Identifier Names)

IdentifierName 中允许使用 Unicode 转义序列,它们贡献单个等于该 UnicodeEscapeSequence 的 IdentifierCodePoint 的 Unicode 码点。前导的 \ 不贡献码点。UnicodeEscapeSequence 不能用于为本来无效的 IdentifierName 提供码点。换言之,如果将 \ UnicodeEscapeSequence 序列替换为其贡献的 SourceCharacter,结果仍须是一个有效的 IdentifierName,并且与原始 IdentifierName 拥有完全相同的 SourceCharacter 序列。本规范中对 IdentifierName 的所有解释都基于其实际码点,无论是否通过转义序列写出。

两个根据 Unicode 标准规范等价的 IdentifierName,除非在替换每个 UnicodeEscapeSequence 后由完全相同的码点序列表示,否则相等。

12.7.1.1 静态语义:早期错误 (Static Semantics: Early Errors)

IdentifierStart :: \ UnicodeEscapeSequence IdentifierPart :: \ UnicodeEscapeSequence

12.7.1.2 静态语义:IdentifierCodePoints

The syntax-directed operation 静态语义:IdentifierCodePoints takes no arguments and returns 码点列表 (a List of code points). It is defined piecewise over the following productions:

IdentifierName :: IdentifierStart
  1. cpIdentifierStart 的 IdentifierCodePoint。
  2. 返回 « cp »。
IdentifierName :: IdentifierName IdentifierPart
  1. cps 为所派生 IdentifierName 的 IdentifierCodePoints。
  2. cpIdentifierPart 的 IdentifierCodePoint。
  3. 返回 cps 与 « cp » 的列表连接。

12.7.1.3 静态语义:IdentifierCodePoint

The syntax-directed operation 静态语义:IdentifierCodePoint takes no arguments and returns 一个码点 (a code point). It is defined piecewise over the following productions:

IdentifierStart :: IdentifierStartChar
  1. 返回 IdentifierStartChar 匹配的码点。
IdentifierPart :: IdentifierPartChar
  1. 返回 IdentifierPartChar 匹配的码点。
UnicodeEscapeSequence :: u Hex4Digits
  1. 返回数值为 Hex4Digits 的 MV 的码点。
UnicodeEscapeSequence :: u{ CodePoint }
  1. 返回数值为 CodePoint 的 MV 的码点。

12.7.2 关键字与保留字 (Keywords and Reserved Words)

关键字 (keyword) 是匹配 IdentifierName 且具有句法用途的记号;即出现在某个句法产生式中以打字机字体(固定宽度)字面形式的词。ECMAScript 的关键字包括 ifwhileasyncawait 等。

保留字 (reserved word) 是不能用作标识符的 IdentifierName。许多关键字是保留字,但有些不是;还有一些只在特定上下文中被保留。ifwhile 是保留字。await 仅在 async 函数与模块内部被保留。async 不是保留字;它可自由用作变量名或语句标签。

本规范结合语法产生式与早期错误规则来指明哪些名称是有效标识符,哪些是保留字。下列 ReservedWord 列表中除 awaityield 外的所有记号无条件被保留。awaityield 的例外通过带参数的句法产生式在 13.1 中指定。最后,多条早期错误规则限制有效标识符集合,见 13.1.114.3.1.114.7.5.115.7.1。概括而言,标识符名称有五类:

  • 始终允许且不是关键字的,如 MathwindowtoString_

  • 永不允许的,即下表 ReservedWord(除 awaityield);

  • 上下文允许的,即 awaityield

  • 在严格模式中上下文不允许的:letstaticimplementsinterfacepackageprivateprotectedpublic

  • 始终允许但在某些句法产生式(Identifier 不允许处)又作为关键字出现的:asasyncfromgetmetaofsettarget

条件关键字 (conditional keyword)上下文关键字 (contextual keyword) 常用于指代后三类,它们在某些上下文可作标识符,在另一些上下文作关键字。

Syntax

ReservedWord :: one of await break case catch class const continue debugger default delete do else enum export extends false finally for function if import in instanceof new null return super switch this throw true try typeof var void while with yield Note 1

依据 5.1.5,语法中的关键字匹配特定 SourceCharacter 序列的字面串。关键字中的码点不能通过 \ UnicodeEscapeSequence 表达。

IdentifierName 可包含 \ UnicodeEscapeSequence,但不能通过拼写 els\u{65} 来声明名为 “else” 的变量。13.1.1早期错误规则会排除 StringValue 与保留字相同的标识符。

Note 2

enum 当前尚未作为关键字使用。它是一个未来保留字,为未来语言扩展保留。

同样地,implementsinterfacepackageprivateprotectedpublic 在严格模式中是未来保留字。

Note 3

argumentseval 不是关键字,但在严格模式中有一些限制。参见 13.1.18.6.415.2.115.5.115.6.115.8.1

12.8 标点符号 (Punctuators)

Syntax

Punctuator :: OptionalChainingPunctuator OtherPunctuator OptionalChainingPunctuator :: ?. [lookahead ∉ DecimalDigit] OtherPunctuator :: one of { ( ) [ ] . ... ; , < > <= >= == != === !== + - * % ** ++ -- << >> >>> & | ^ ! ~ && || ?? ? : = += -= *= %= **= <<= >>= >>>= &= |= ^= &&= ||= ??= => DivPunctuator :: / /= RightBracePunctuator :: }

12.9 字面量 (Literals)

12.9.1 Null 字面量 (Null Literals)

Syntax

NullLiteral :: null

12.9.2 布尔字面量 (Boolean Literals)

Syntax

BooleanLiteral :: true false

12.9.3 数值字面量 (Numeric Literals)

Syntax

NumericLiteralSeparator :: _ NumericLiteral :: DecimalLiteral DecimalBigIntegerLiteral NonDecimalIntegerLiteral[+Sep] NonDecimalIntegerLiteral[+Sep] BigIntLiteralSuffix LegacyOctalIntegerLiteral DecimalBigIntegerLiteral :: 0 BigIntLiteralSuffix NonZeroDigit DecimalDigits[+Sep]opt BigIntLiteralSuffix NonZeroDigit NumericLiteralSeparator DecimalDigits[+Sep] BigIntLiteralSuffix NonDecimalIntegerLiteral[Sep] :: BinaryIntegerLiteral[?Sep] OctalIntegerLiteral[?Sep] HexIntegerLiteral[?Sep] BigIntLiteralSuffix :: n DecimalLiteral :: DecimalIntegerLiteral . DecimalDigits[+Sep]opt ExponentPart[+Sep]opt . DecimalDigits[+Sep] ExponentPart[+Sep]opt DecimalIntegerLiteral ExponentPart[+Sep]opt DecimalIntegerLiteral :: 0 NonZeroDigit NonZeroDigit NumericLiteralSeparatoropt DecimalDigits[+Sep] NonOctalDecimalIntegerLiteral DecimalDigits[Sep] :: DecimalDigit DecimalDigits[?Sep] DecimalDigit [+Sep] DecimalDigits[+Sep] NumericLiteralSeparator DecimalDigit DecimalDigit :: one of 0 1 2 3 4 5 6 7 8 9 NonZeroDigit :: one of 1 2 3 4 5 6 7 8 9 ExponentPart[Sep] :: ExponentIndicator SignedInteger[?Sep] ExponentIndicator :: one of e E SignedInteger[Sep] :: DecimalDigits[?Sep] + DecimalDigits[?Sep] - DecimalDigits[?Sep] BinaryIntegerLiteral[Sep] :: 0b BinaryDigits[?Sep] 0B BinaryDigits[?Sep] BinaryDigits[Sep] :: BinaryDigit BinaryDigits[?Sep] BinaryDigit [+Sep] BinaryDigits[+Sep] NumericLiteralSeparator BinaryDigit BinaryDigit :: one of 0 1 OctalIntegerLiteral[Sep] :: 0o OctalDigits[?Sep] 0O OctalDigits[?Sep] OctalDigits[Sep] :: OctalDigit OctalDigits[?Sep] OctalDigit [+Sep] OctalDigits[+Sep] NumericLiteralSeparator OctalDigit LegacyOctalIntegerLiteral :: 0 OctalDigit LegacyOctalIntegerLiteral OctalDigit NonOctalDecimalIntegerLiteral :: 0 NonOctalDigit LegacyOctalLikeDecimalIntegerLiteral NonOctalDigit NonOctalDecimalIntegerLiteral DecimalDigit LegacyOctalLikeDecimalIntegerLiteral :: 0 OctalDigit LegacyOctalLikeDecimalIntegerLiteral OctalDigit OctalDigit :: one of 0 1 2 3 4 5 6 7 NonOctalDigit :: one of 8 9 HexIntegerLiteral[Sep] :: 0x HexDigits[?Sep] 0X HexDigits[?Sep] HexDigits[Sep] :: HexDigit HexDigits[?Sep] HexDigit [+Sep] HexDigits[+Sep] NumericLiteralSeparator HexDigit HexDigit :: one of 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F

NumericLiteral 之后紧接的下一个 SourceCharacter 不能是 IdentifierStartDecimalDigit

Note

例如:3in 是错误,而不是两个输入元素 3in

12.9.3.1 静态语义:早期错误 (Static Semantics: Early Errors)

NumericLiteral :: LegacyOctalIntegerLiteral DecimalIntegerLiteral :: NonOctalDecimalIntegerLiteral
  • 若 IsStrict(this production) 为 true 则为语法错误。
Note
在非严格代码中,该语法为 Legacy。

12.9.3.2 静态语义:MV (Static Semantics: MV)

数值字面量表示 Number 类型BigInt 类型的值。

12.9.3.3 静态语义:NumericValue

The syntax-directed operation 静态语义:NumericValue takes no arguments and returns Number 或 BigInt. It is defined piecewise over the following productions:

NumericLiteral :: DecimalLiteral
  1. 返回 RoundMVResult(DecimalLiteral 的 MV)。
NumericLiteral :: NonDecimalIntegerLiteral
  1. 返回 𝔽(NonDecimalIntegerLiteral 的 MV)。
NumericLiteral :: LegacyOctalIntegerLiteral
  1. 返回 𝔽(LegacyOctalIntegerLiteral 的 MV)。
NumericLiteral :: NonDecimalIntegerLiteral BigIntLiteralSuffix
  1. 返回 NonDecimalIntegerLiteral 的 MV 对应的 BigInt 值
DecimalBigIntegerLiteral :: 0 BigIntLiteralSuffix
  1. 返回 0
DecimalBigIntegerLiteral :: NonZeroDigit BigIntLiteralSuffix
  1. 返回 NonZeroDigit 的 MV 对应的 BigInt 值
DecimalBigIntegerLiteral :: NonZeroDigit DecimalDigits BigIntLiteralSuffix NonZeroDigit NumericLiteralSeparator DecimalDigits BigIntLiteralSuffix
  1. nDecimalDigits 中(排除所有 NumericLiteralSeparator)码点数。
  2. mv 为 (NonZeroDigit 的 MV × 10n) + DecimalDigits 的 MV。
  3. 返回 (mv)。

12.9.4 字符串字面量 (String Literals)

Note 1

字符串字面量是 0 个或更多 Unicode 码点,被单引号或双引号包围。Unicode 码点也可用转义序列表达。除闭合引号码点、U+005C (REVERSE SOLIDUS)、U+000D (CARRIAGE RETURN)、U+000A (LINE FEED) 外,所有码点都可直接出现在字符串字面量中。任何码点都可以转义形式出现。字符串字面量求值为 ECMAScript String 值。生成这些 String 值时 Unicode 码点按 11.1.1 中定义进行 UTF-16 编码。基本多文种平面 (BMP) 内的码点编码为单个代码单元,其它码点编码为两个代码单元。

Syntax

StringLiteral :: " DoubleStringCharactersopt " ' SingleStringCharactersopt ' DoubleStringCharacters :: DoubleStringCharacter DoubleStringCharactersopt SingleStringCharacters :: SingleStringCharacter SingleStringCharactersopt DoubleStringCharacter :: SourceCharacter but not one of " or \ or LineTerminator <LS> <PS> \ EscapeSequence LineContinuation SingleStringCharacter :: SourceCharacter but not one of ' or \ or LineTerminator <LS> <PS> \ EscapeSequence LineContinuation LineContinuation :: \ LineTerminatorSequence EscapeSequence :: CharacterEscapeSequence 0 [lookahead ∉ DecimalDigit] LegacyOctalEscapeSequence NonOctalDecimalEscapeSequence HexEscapeSequence UnicodeEscapeSequence CharacterEscapeSequence :: SingleEscapeCharacter NonEscapeCharacter SingleEscapeCharacter :: one of ' " \ b f n r t v NonEscapeCharacter :: SourceCharacter but not one of EscapeCharacter or LineTerminator EscapeCharacter :: SingleEscapeCharacter DecimalDigit x u LegacyOctalEscapeSequence :: 0 [lookahead ∈ { 8, 9 }] NonZeroOctalDigit [lookahead ∉ OctalDigit] ZeroToThree OctalDigit [lookahead ∉ OctalDigit] FourToSeven OctalDigit ZeroToThree OctalDigit OctalDigit NonZeroOctalDigit :: OctalDigit but not 0 ZeroToThree :: one of 0 1 2 3 FourToSeven :: one of 4 5 6 7 NonOctalDecimalEscapeSequence :: one of 8 9 HexEscapeSequence :: x HexDigit HexDigit UnicodeEscapeSequence :: u Hex4Digits u{ CodePoint } Hex4Digits :: HexDigit HexDigit HexDigit HexDigit

非终结符 HexDigit 定义见 12.9.3SourceCharacter 定义见 11.1

Note 2

<LF> 与 <CR> 不能出现在字符串字面量中,除非作为 LineContinuation 的一部分以生成空码点序列。要在字符串字面量值中包含它们,应使用 \n\u000A 等转义序列。

12.9.4.1 静态语义:早期错误 (Static Semantics: Early Errors)

EscapeSequence :: LegacyOctalEscapeSequence NonOctalDecimalEscapeSequence
  • 若 IsStrict(this production) 为 true 则为语法错误。
Note 1
在非严格代码中,该语法为 Legacy。
Note 2

字符串字面量可能位于使封闭代码进入 严格模式 的 Use Strict 指令之前,实现必须谨慎对这些字面量执行上述规则。例如,下列源码包含语法错误:

function invalid() { "\7"; "use strict"; }

12.9.4.2 静态语义:SV

The syntax-directed operation 静态语义:SV takes no arguments and returns 一个 String.

字符串字面量表示 String 类型值。SV 通过对字面量各部分的递归应用生成 String 值。在此过程中,字符串字面量中的某些 Unicode 码点按下文或 12.9.3 描述被视为具有数学值

Table 35: 字符串单字符转义序列 (String Single Character Escape Sequences)
转义序列 (Escape Sequence) 代码单元值 (Code Unit Value) Unicode 字符名 (Unicode Character Name) 符号 (Symbol)
\b 0x0008 BACKSPACE <BS>
\t 0x0009 CHARACTER TABULATION <HT>
\n 0x000A LINE FEED (LF) <LF>
\v 0x000B LINE TABULATION <VT>
\f 0x000C FORM FEED (FF) <FF>
\r 0x000D CARRIAGE RETURN (CR) <CR>
\" 0x0022 QUOTATION MARK "
\' 0x0027 APOSTROPHE '
\\ 0x005C REVERSE SOLIDUS \

12.9.4.3 静态语义:MV

12.9.5 正则表达式字面量 (Regular Expression Literals)

Note 1

正则表达式字面量是一个输入元素,每次求值它都会转换为一个 RegExp 对象(见 22.2)。程序中两个正则字面量即便内容相同,求值得到的两个正则对象也永远不会 ===。RegExp 对象也可在运行时通过 new RegExp 或以函数形式调用构造器创建(见 22.2.4)。

下列产生式描述正则表达式字面量的语法,供输入元素扫描器定位字面量结束。由 RegularExpressionBodyRegularExpressionFlags 组成的源码随后再用更严格的 ECMAScript 正则语法(22.2.1)解析。

实现可扩展 22.2.1 定义的 ECMAScript 正则语法,但不得扩展以下定义的 RegularExpressionBodyRegularExpressionFlags 及其依赖的产生式。

Syntax

RegularExpressionLiteral :: / RegularExpressionBody / RegularExpressionFlags RegularExpressionBody :: RegularExpressionFirstChar RegularExpressionChars RegularExpressionChars :: [empty] RegularExpressionChars RegularExpressionChar RegularExpressionFirstChar :: RegularExpressionNonTerminator but not one of * or \ or / or [ RegularExpressionBackslashSequence RegularExpressionClass RegularExpressionChar :: RegularExpressionNonTerminator but not one of \ or / or [ RegularExpressionBackslashSequence RegularExpressionClass RegularExpressionBackslashSequence :: \ RegularExpressionNonTerminator RegularExpressionNonTerminator :: SourceCharacter but not LineTerminator RegularExpressionClass :: [ RegularExpressionClassChars ] RegularExpressionClassChars :: [empty] RegularExpressionClassChars RegularExpressionClassChar RegularExpressionClassChar :: RegularExpressionNonTerminator but not one of ] or \ RegularExpressionBackslashSequence RegularExpressionFlags :: [empty] RegularExpressionFlags IdentifierPartChar Note 2

正则字面量不能为空;序列 // 表示单行注释而不是空正则。若需空正则,使用 /(?:)/

12.9.5.1 静态语义:BodyText

The syntax-directed operation 静态语义:BodyText takes no arguments and returns source text. It is defined piecewise over the following productions:

RegularExpressionLiteral :: / RegularExpressionBody / RegularExpressionFlags
  1. 返回识别为 RegularExpressionBody 的源码文本。

12.9.5.2 静态语义:FlagText

The syntax-directed operation 静态语义:FlagText takes no arguments and returns source text. It is defined piecewise over the following productions:

RegularExpressionLiteral :: / RegularExpressionBody / RegularExpressionFlags
  1. 返回识别为 RegularExpressionFlags 的源码文本。

12.9.6 模板字面量词法组件 (Template Literal Lexical Components)

Syntax

Template :: NoSubstitutionTemplate TemplateHead NoSubstitutionTemplate :: ` TemplateCharactersopt ` TemplateHead :: ` TemplateCharactersopt ${ TemplateSubstitutionTail :: TemplateMiddle TemplateTail TemplateMiddle :: } TemplateCharactersopt ${ TemplateTail :: } TemplateCharactersopt ` TemplateCharacters :: TemplateCharacter TemplateCharactersopt TemplateCharacter :: $ [lookahead ≠ {] \ TemplateEscapeSequence \ NotEscapeSequence LineContinuation LineTerminatorSequence SourceCharacter but not one of ` or \ or $ or LineTerminator TemplateEscapeSequence :: CharacterEscapeSequence 0 [lookahead ∉ DecimalDigit] HexEscapeSequence UnicodeEscapeSequence NotEscapeSequence :: 0 DecimalDigit DecimalDigit but not 0 x [lookahead ∉ HexDigit] x HexDigit [lookahead ∉ HexDigit] u [lookahead ∉ HexDigit] [lookahead ≠ {] u HexDigit [lookahead ∉ HexDigit] u HexDigit HexDigit [lookahead ∉ HexDigit] u HexDigit HexDigit HexDigit [lookahead ∉ HexDigit] u { [lookahead ∉ HexDigit] u { NotCodePoint [lookahead ∉ HexDigit] u { CodePoint [lookahead ∉ HexDigit] [lookahead ≠ }] NotCodePoint :: HexDigits[~Sep] but only if the MV of HexDigits > 0x10FFFF CodePoint :: HexDigits[~Sep] but only if the MV of HexDigits ≤ 0x10FFFF Note

TemplateSubstitutionTailInputElementTemplateTail 可选词法目标使用。

12.9.6.1 静态语义:TV

The syntax-directed operation 静态语义:TV takes no arguments and returns String 或 undefined. 模板字面量组件由 TV 解释为 String 类型值。TV 用来构造模板对象的索引组件(俗称 template values)。在 TV 中,转义序列被替换为其表示码点的 UTF-16 代码单元。

12.9.6.2 静态语义:TRV

The syntax-directed operation 静态语义:TRV takes no arguments and returns String. 模板字面量组件由 TRV 解释为 String 类型值。TRV 用来构造模板对象的原始组件(raw values)。TRV 与 TV 类似,区别在于 TRV 中转义序列按字面出现形式解释。

Note

TV 不包含 LineContinuation 的代码单元,而 TRV 包含。<CR><LF> 与 <CR> LineTerminatorSequence 在 TV 与 TRV 中均规范化为 <LF>。要包含 <CR> 或 <CR><LF>,需要显式 TemplateEscapeSequence

12.10 自动分号插入 (Automatic Semicolon Insertion)

大多数 ECMAScript 语句与声明必须以分号结束。此类分号可在源码中显式出现。为方便起见,在某些情形下可以省略;在这些情形中,认为分号被自动插入到源码记号流中。

12.10.1 自动分号插入的规则 (Rules of Automatic Semicolon Insertion)

下列规则中,“token” 指根据 12 所述当前词法目标符号识别出的实际词法记号。

分号插入有三条基本规则:

  1. 当从左到右解析源码时遇到一个不被任何语法产生式允许的记号(称为 违规记号 (offending token))时,如果满足以下任一条件,则在其前自动插入分号:

    • 违规记号与前一个记号之间至少有一个 LineTerminator
    • 违规记号是 }
    • 前一个记号是 ),且插入的分号会被解析为 do-while 语句(14.7.2)的结束分号。
  2. 当从左到右解析时,如果到达输入记号流末尾且解析器无法将其解析为目标非终结符的单一实例,则在末尾自动插入分号。
  3. 当从左到右解析时遇到的记号在某个产生式中被允许,但该产生式是受限产生式 (restricted production) 且该记号将成为紧随 “[no LineTerminator here]” 注解之后的终结符或非终结符的首记号(故称为受限记号),且受限记号与前一记号之间至少有一个 LineTerminator,则在该受限记号前自动插入分号。

然而,上述规则受一个额外覆盖条件:若自动插入的分号会被解析为空语句,或将成为 for 语句(见 14.7.4)头部的两个分号之一,则不会自动插入。

Note

以下是语法中唯一的受限产生式:

UpdateExpression[Yield, Await] : LeftHandSideExpression[?Yield, ?Await] [no LineTerminator here] ++ LeftHandSideExpression[?Yield, ?Await] [no LineTerminator here] -- ContinueStatement[Yield, Await] : continue ; continue [no LineTerminator here] LabelIdentifier[?Yield, ?Await] ; BreakStatement[Yield, Await] : break ; break [no LineTerminator here] LabelIdentifier[?Yield, ?Await] ; ReturnStatement[Yield, Await] : return ; return [no LineTerminator here] Expression[+In, ?Yield, ?Await] ; ThrowStatement[Yield, Await] : throw [no LineTerminator here] Expression[+In, ?Yield, ?Await] ; YieldExpression[In, Await] : yield yield [no LineTerminator here] AssignmentExpression[?In, +Yield, ?Await] yield [no LineTerminator here] * AssignmentExpression[?In, +Yield, ?Await] ArrowFunction[In, Yield, Await] : ArrowParameters[?Yield, ?Await] [no LineTerminator here] => ConciseBody[?In] AsyncFunctionDeclaration[Yield, Await, Default] : async [no LineTerminator here] function BindingIdentifier[?Yield, ?Await] ( FormalParameters[~Yield, +Await] ) { AsyncFunctionBody } [+Default] async [no LineTerminator here] function ( FormalParameters[~Yield, +Await] ) { AsyncFunctionBody } AsyncFunctionExpression : async [no LineTerminator here] function BindingIdentifier[~Yield, +Await]opt ( FormalParameters[~Yield, +Await] ) { AsyncFunctionBody } AsyncMethod[Yield, Await] : async [no LineTerminator here] ClassElementName[?Yield, ?Await] ( UniqueFormalParameters[~Yield, +Await] ) { AsyncFunctionBody } AsyncGeneratorDeclaration[Yield, Await, Default] : async [no LineTerminator here] function * BindingIdentifier[?Yield, ?Await] ( FormalParameters[+Yield, +Await] ) { AsyncGeneratorBody } [+Default] async [no LineTerminator here] function * ( FormalParameters[+Yield, +Await] ) { AsyncGeneratorBody } AsyncGeneratorExpression : async [no LineTerminator here] function * BindingIdentifier[+Yield, +Await]opt ( FormalParameters[+Yield, +Await] ) { AsyncGeneratorBody } AsyncGeneratorMethod[Yield, Await] : async [no LineTerminator here] * ClassElementName[?Yield, ?Await] ( UniqueFormalParameters[+Yield, +Await] ) { AsyncGeneratorBody } AsyncArrowFunction[In, Yield, Await] : async [no LineTerminator here] AsyncArrowBindingIdentifier[?Yield] [no LineTerminator here] => AsyncConciseBody[?In] CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await] [no LineTerminator here] => AsyncConciseBody[?In] AsyncArrowHead : async [no LineTerminator here] ArrowFormalParameters[~Yield, +Await]

这些受限产生式的实际效果:

  • 当遇到可被解析为后缀 ++-- 运算符的记号,且其与前一记号之间至少有一个 LineTerminator,则在该运算符前自动插入分号。
  • 当遇到 continuebreakreturnthrowyield,且其后一个记号前存在 LineTerminator,则在该关键字后自动插入分号。
  • 当箭头函数参数后紧跟的 => 前出现 LineTerminator 时,自动插入分号并导致该 => 处语法错误。
  • async 后在期望的 functionIdentifierName( 之前出现 LineTerminator,自动插入分号且后续不再与该 async 归为同一表达式或类元素。
  • async 后在期望的 * 之前出现 LineTerminator,自动插入分号并导致该标点语法错误。

对程序员的实践建议:

  • 后缀 ++ / -- 应与其操作数位于同一行。
  • returnthrow 语句中的 Expressionyield 表达式中的 AssignmentExpression 应与关键字位于同一行。
  • breakcontinue 语句中的 LabelIdentifier 应与各自关键字在同一行。
  • 箭头函数参数部分结尾与 => 应位于同一行。
  • 异步函数或方法前的 async 应与紧随其后的记号在同一行。

12.10.2 自动分号插入示例 (Examples of Automatic Semicolon Insertion)

本节为非规范性内容。

源码

{ 1 2 } 3

即便考虑自动分号插入规则,也不是有效 ECMAScript 语句。相比之下,源码

{ 1
2 } 3

也不是有效语句,但会被自动分号插入转换为:

{ 1
;2 ;} 3;

其为有效语句。

源码

for (a; b
)

不是有效语句,且不会被修改,因为分号对 for 头部必要;自动分号插入不会插入 for 头部的两个分号之一。

源码

return
a + b

被转换为:

return;
a + b;
Note 1

a + b 不作为 return 语句返回值,因为 LineTerminator 将其与 return 分隔。

源码

a = b
++c

转换为:

a = b;
++c;
Note 2

++ 不作为应用于 b 的后缀运算符,因为 b++ 之间存在 LineTerminator

源码

if (a > b)
else c = d

不是有效语句,且在 else 前不会自动插入分号,即便此处没有适用的语法产生式,因为插入分号会形成空语句。

源码

a = b + c
(d + e).print()

不会 被转换,因为第二行以括号表达式开始可被解释为函数调用的实参列表:

a = b + c(d + e).print()

若赋值语句必须以左括号开始,建议在前一语句末尾显式写分号,而不是依赖自动分号插入。

12.10.3 自动分号插入的有趣情形 (Interesting Cases of Automatic Semicolon Insertion)

本节为非规范性内容。

ECMAScript 程序可以通过依赖自动分号插入以极少分号的风格编写。如前述,分号不会在每个换行处插入,并且插入可能依赖跨行的多个记号。

随着新语法特性的加入,可能增加新的产生式,使之前依赖自动分号插入的行在解析时改变其产生式。

本节中,若某处是否插入分号取决于其前源码,则视为“有趣”情形。剩余内容描述本版本 ECMAScript 中若干此类情形。

12.10.3.1 语句列表中的自动分号插入有趣情形 (Interesting Cases ... in Statement Lists)

StatementList 中,许多 StatementListItem 以可省略的分号结尾。根据上述规则,在一行表达式结尾处,若下一行以以下任一开头则需要分号:

  • 左括号 (()。缺少分号会将两行合并为 CallExpression
  • 左方括号 ([)。缺少分号会解析为属性访问而非 ArrayLiteralArrayAssignmentPattern
  • 模板字面量 (`)。缺少分号会合并为带前一个表达式为 MemberExpression 的标签模板(13.3.11)。
  • 一元 +-。缺少分号会被解释为相应二元运算的一部分。
  • 正则表达式字面量。缺少分号时,若正则含标志,可能被解析为 / MultiplicativeOperator

12.10.3.2 与 “[no LineTerminator here]” 相关的自动分号插入情形 (Cases ... “[no LineTerminator here]”)

本节为非规范性内容。

ECMAScript 包含含 “[no LineTerminator here]” 的语法产生式。这些产生式有时用于在语法中表达可选操作数。在这些位置引入 LineTerminator 会通过采用不含可选操作数的产生式改变源码的语法结构。

本节其余内容描述本版本中使用 “[no LineTerminator here]” 的若干产生式。

12.10.3.2.1 含可选操作数与 “[no LineTerminator here]” 的产生式列表