?um/p1-90`ECMAScript
在若干情况下,词法输入元素的识别会对消费这些输入元素的句法语法上下文敏感。这要求词法语法具有多个
使用多个词法目标可确保不存在会影响自动分号插入的词法歧义。例如,不存在同时允许前导除法或除法赋值,以及前导
a = b
/hi/g.exec(c).map(d);
其中
a = b / hi / g.exec(c).map(d);
Unicode 格式控制字符(即 Unicode 字符数据库中类别为 “Cf” 的字符,例如 LEFT-TO-RIGHT MARK 或 RIGHT-TO-LEFT MARK)是在缺少用于此目的的更高级协议(例如标记语言)时,用于控制一段文本格式的控制码。
允许格式控制字符出现在源文本中,有助于编辑和显示。所有格式控制字符都可以在注释中使用,也可以在字符串字面量、模板字面量和正则表达式字面量中使用。
U+FEFF (ZERO WIDTH NO-BREAK SPACE) 是一种格式控制字符,主要用于文本开头,以标记其为 Unicode 并允许检测文本的编码和字节顺序。用于此目的的 <ZWNBSP> 字符有时也可能出现在文本开头之后,例如作为连接文件的结果。在 ECMAScript 源文本中,在注释、字符串字面量、模板字面量和正则表达式字面量之外,<ZWNBSP> 码点会被当作空白字符处理(参见
空白码点用于提高源文本可读性,并将 token(不可分割的词法单元)彼此分隔开,但除此之外并不重要。空白码点可以出现在任意两个 token 之间,也可以出现在输入的开头或结尾。空白码点可以出现在
ECMAScript 空白码点列于
| 码点 | 名称 | 缩写 |
|---|---|---|
U+0009
|
CHARACTER TABULATION | <TAB> |
U+000B
|
LINE TABULATION | <VT> |
U+000C
|
FORM FEED (FF) | <FF> |
U+FEFF
|
ZERO WIDTH NO-BREAK SPACE | <ZWNBSP> |
| 一般类别 “Space_Separator” 中的任何码点 | <USP> |
U+0020 (SPACE) 和 U+00A0 (NO-BREAK SPACE) 码点是 <USP> 的一部分。
除了
与空白码点类似,行终止符码点用于提高源文本可读性,并将 token(不可分割的词法单元)彼此分隔开。不过,与空白码点不同,行终止符会对句法语法的行为产生一些影响。一般而言,行终止符可以出现在任意两个 token 之间,但句法语法在少数位置禁止它们出现。行终止符还会影响自动分号插入过程(
行终止符可以出现在
行终止符\s 类匹配的空白码点集合内。
ECMAScript 行终止符码点列于
| 码点 | Unicode 名称 | 缩写 |
|---|---|---|
U+000A
|
LINE FEED (LF) | <LF> |
U+000D
|
CARRIAGE RETURN (CR) | <CR> |
U+2028
|
LINE SEPARATOR | <LS> |
U+2029
|
PARAGRAPH SEPARATOR | <PS> |
只有
注释可以是单行或多行。多行注释不能嵌套。
因为单行注释可以// 标记到行尾的所有码点组成。不过,行尾的
注释的行为类似于空白,并会被丢弃;但如果
本节中的若干产生式在
Hashbang 注释对位置敏感,并且像其他类型的注释一样,会从句法语法的输入元素流中丢弃。
本标准指定了特定码点的添加:U+0024 (DOLLAR SIGN) 和 U+005F (LOW LINE) 允许出现在
非终结符
非终结符 _。
具有 Unicode 属性 “ID_Start” 和 “ID_Continue” 的码点集合分别包括具有 Unicode 属性 “Other_ID_Start” 和 “Other_ID_Continue” 的码点。
Unicode 转义序列允许出现在 \ 不贡献任何码点。\
根据 Unicode 标准规范等价的两个
The syntax-directed operation IdentifierCodePoints takes no arguments and returns a
The syntax-directed operation IdentifierCodePoint takes no arguments and returns a code point. It is defined piecewise over the following productions:
关键字是一个匹配 fixed width 字体字面出现在某个句法产生式中。ECMAScript 的关键字包括 if、while、async、await 以及许多其他关键字。
保留字是不能用作标识符的 if 和 while 是保留字。await 只在 async 函数和模块内部保留。async 不是保留字;它可以不受限制地用作变量名或语句标签。
本规范使用语法产生式和await 和 yield 外,都无条件保留。await 和 yield 的例外在
始终允许作为标识符且不是关键字的名称,例如 Math、window、toString 和 _;
永远不允许作为标识符的名称,即下方列出的 await 和 yield;
上下文允许作为标识符的名称,即 await 和 yield;
在严格模式代码中,上下文禁止作为标识符的名称:let、static、implements、interface、package、private、protected 和 public;
始终允许作为标识符,但也在某些句法产生式中、在不允许 as、async、from、get、meta、of、set 和 target。
术语 条件关键字或 上下文关键字 有时用于指代落入后三类的关键字,因此它们在某些上下文中可用作标识符,而在其他上下文中可用作关键字。
根据 \
\ els\u{65} 来声明一个名为 “else” 的变量。
enum 目前在本规范中未用作关键字。它是未来保留字,预留用于未来语言扩展中的关键字。
类似地,implements、interface、package、private、protected 和 public 是严格模式代码中的未来保留字。
紧跟在
例如:3in 是错误,而不是两个输入元素 3 和 in。
数值字面量表示
The syntax-directed operation NumericValue takes no arguments and returns a Number or a BigInt. It is defined piecewise over the following productions:
字符串字面量是 0 个或多个
非终结符
<LF> 和 <CR> 不能出现在字符串字面量中,除非作为 \n 或 \u000A 这样的转义序列。
字符串字面量可能出现在使包围代码进入
function invalid() { "\7"; "use strict"; }
The syntax-directed operation SV takes no arguments and returns a String.
字符串字面量表示
| 转义序列 | 代码单元值 | Unicode 字符名称 | 符号 |
|---|---|---|---|
\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 |
\
|
下面的产生式描述正则表达式字面量的语法,并由输入元素扫描器用于查找正则表达式字面量的结束位置。随后,构成
实现可以扩展
正则表达式字面量不得为空;代码单元序列 // 会开始单行注释,而不是表示空正则表达式字面量。要指定空正则表达式,请使用:/(?:)/。
The syntax-directed operation BodyText takes no arguments and returns source text. It is defined piecewise over the following productions:
The syntax-directed operation FlagText takes no arguments and returns source text. It is defined piecewise over the following productions:
The syntax-directed operation TV takes no arguments and returns a String or
The syntax-directed operation TRV takes no arguments and returns a String. 模板字面量组件由 TRV 解释为
大多数 ECMAScript 语句和声明必须以分号终止。这类分号始终可以显式出现在源文本中。不过,为了方便,在某些情况下,这类分号可以从源文本中省略。对这些情况的描述方式是:在这些情况下,分号会被自动插入到源代码 token 流中。
在以下规则中,“token” 指的是使用当前词法
分号插入有三条基本规则:
当源文本从左到右解析时,遇到一个不被语法任何产生式允许的 token(称为违规 token)时,如果以下一个或多个条件为真,则会在该违规 token 之前自动插入一个分号:
}。
),且插入的分号随后会被解析为 do-while 语句(不过,前述规则还有一个额外的覆盖条件:如果插入的分号随后会被解析为空语句,或者该分号会成为 for 语句头部中的两个分号之一(参见
以下是语法中仅有的受限产生式:
这些受限产生式的实际效果如下:
++ 或 -- 标记视为后缀运算符的位置遇到该标记,并且前一个标记与 ++ 或 -- 标记之间至少出现了一个 ++ 或 -- 标记之前自动插入分号。
using 标记,并且在 using 标记之后自动插入分号。
continue、break、return、throw 或 yield 标记,并且在下一个标记之前遇到 continue、break、return、throw 或 yield 标记之后自动插入分号。
=> 标记之前跟着 async 标记后面在 function、( 标记之前跟着 async 标记不会被视为与后续标记属于同一个表达式或类元素。
async 标记后面在 * 标记之前跟着 由此给 ECMAScript 程序员得出的实际建议是:
++ 或 -- 运算符应与其操作数位于同一行。
using 声明中的 using 标记在同一行开始。
return 或 throw 语句中的 yield 表达式中的 return、throw 或 yield 标记在同一行开始。
break 或 continue 语句中的 break 或 continue 标记位于同一行。
=> 应位于同一行。
async 标记应与紧随其后的标记位于同一行。
源文本
{ 1 2 } 3
即使使用自动分号插入规则,也不是 ECMAScript 语法中的有效句子。相比之下,源文本
{ 1
2 } 3
同样不是有效的 ECMAScript 句子,但会通过自动分号插入转换为以下内容:
{ 1
;2 ;} 3;
这是有效的 ECMAScript 句子。
源文本
for (a; b
)
不是有效的 ECMAScript 句子,并且不会被自动分号插入改变,因为该分号是 for 语句头部所需的。自动分号插入永远不会插入 for 语句头部中的两个分号之一。
源文本
return
a + b
会通过自动分号插入转换为以下内容:
return;
a + b;
表达式 a + b 不会被当作 return 语句要返回的值,因为 return 分隔开。
源文本
a = b
++c
会通过自动分号插入转换为以下内容:
a = b;
++c;
token ++ 不会被当作应用于变量 b 的后缀运算符,因为 b 和 ++ 之间出现了
源文本
if (a > b)
else c = d
不是有效的 ECMAScript 句子,并且不会在 else token 之前通过自动分号插入改变,即使在该点没有语法产生式适用,因为自动插入的分号随后会被解析为空语句。
源文本
a = b + c
(d + e).print()
不会通过自动分号插入转换,因为第二行开头的带括号表达式可以被解释为函数调用的实参列表:
a = b + c(d + e).print()
在赋值语句必须以左括号开头的情况下,程序员最好在前一个语句末尾提供显式分号,而不是依赖自动分号插入。
ECMAScript 程序可以通过依赖自动分号插入,以很少分号的风格编写。如上所述,分号并不会在每个换行处插入,而且自动分号插入可能依赖跨越行终止符的多个 token。
随着新的句法特性加入 ECMAScript,可能会添加额外的语法产生式,使依赖自动分号插入且位于这些产生式之前的行在解析时改变语法产生式。
就本节而言,如果某个自动分号插入情形是一个可能插入也可能不插入分号的位置,取决于它之前的源文本,则该情形被认为是有趣的。本节其余部分描述此 ECMAScript 版本中若干自动分号插入的有趣情形。
在
()。没有分号时,两行会一起被当作 [)。没有分号时,两行会一起被当作属性访问,而不是 `)。没有分号时,两行会一起被解释为带标签 Template(+ 或 -。没有分号时,两行会一起被解释为对应二元运算符的使用。/ ECMAScript
本节其余部分描述此 ECMAScript 版本中若干使用 “[no