不特定于浏览器/实现,但ECMAScript Language Specification 中的Section 7.9 Automatic Semicolon Insertion 值得一读。
7.9 自动分号插入
某些 ECMAScript 语句(空语句、变量语句、表达式语句、do-while
语句、continue 语句、break 语句、return 语句和 throw 语句)必须是
以分号结尾。这样的分号可能总是显式地出现在源文本中。为了
但是,为了方便起见,在某些情况下,可以从源文本中省略这些分号。这些
通过说分号自动插入源代码令牌来描述情况
在这些情况下进行流式传输。
7.9.1 自动分号插入规则
分号插入的三个基本规则:
-
当程序从左到右解析时,遇到一个标记(称为违规标记)
语法的任何产生式都不允许,则在
如果以下一个或多个条件为真,则违规令牌:
- 违规标记与前一个标记至少由一个 LineTerminator 分隔。
- 有问题的令牌是 }。
当从左到右解析程序时,遇到输入标记流的结尾
并且解析器无法将输入令牌流解析为单个完整的 ECMAScript 程序,则
分号会自动插入到输入流的末尾。
当程序从左到右解析时,遇到某些允许的标记
语法的产生,但产生是受限制的产生,令牌将是第一个
紧跟注释后的终端或非终端的标记?[此处没有 LineTerminator]?内
受限生产(因此这样的令牌称为受限令牌),并且受限令牌是
由至少一个 LineTerminator 与前一个标记分隔,然后自动使用分号
在受限令牌之前插入。
但是,前面的规则还有一个额外的覆盖条件:从不插入分号
如果分号随后将被解析为空语句或该分号将变为
for 语句头中的两个分号之一(见 12.6.3)。
注意以下是语法中唯一受限制的产生式:
后缀表达式:
LeftHandSideExpression [此处没有 LineTerminator] ++
LeftHandSideExpression [这里没有 LineTerminator] --
继续声明:
continue [这里没有 LineTerminator] 标识符;
断句:
break [此处没有 LineTerminator] 标识符;
退货声明:
return [这里没有 LineTerminator] 表达式;
抛出语句:
throw [这里没有 LineTerminator] 表达式;
这些限制生产的实际效果如下:
当遇到解析器将其视为后缀运算符的 ++ 或 -- 标记时,并且至少有一个
LineTerminator 出现在前面的标记和 ++ 或 -- 标记之间,然后自动分号
在 ++ 或 -- 标记之前插入。
当遇到 continue、break、return 或 throw 标记并且之前遇到 LineTerminator
下一个标记,在 continue、break、return 或 throw 标记之后自动插入分号。
给 ECMAScript 程序员的实用建议是:
后缀 ++ 或 -- 运算符应与其操作数出现在同一行。
return 或 throw 语句中的 Expression 应与 return 或 throw 标记在同一行开始。
break 或 continue 语句中的标识符应与 break 或 continue 标记位于同一行。
7.9.2 自动分号插入示例
来源
{ 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 语句要返回的值,因为 a
LineTerminator 将其与令牌返回分开。
来源
a = b
++c
通过自动分号插入转换为以下内容:
a = b;
++c;
注意标记 ++ 不被视为应用于变量 b 的后缀运算符,因为出现了 LineTerminator
在 b 和 ++ 之间。
来源
if (a > b)
else c = d
不是一个有效的 ECMAScript 语句,并且不会通过自动在 else 标记之前插入分号来改变,
即使此时没有产生语法,因为自动插入的分号
然后将被解析为空语句。
来源
a = b + c
(d + e).print()
不会被自动分号插入转换,因为以括号开头的表达式
第二行可以解释为函数调用的参数列表:
a = b + c(d + e).print()
在赋值语句必须以左括号开头的情况下,这是一个好主意
程序员在前面的语句末尾提供一个明确的分号,而不是依赖于
自动插入分号。