美文网首页JavaScript
[ECMAScript] 自动分号插入机制

[ECMAScript] 自动分号插入机制

作者: 何幻 | 来源:发表于2017-10-18 19:59 被阅读20次

1. 插入分号

ECMAScript中,大部分声明和语句,都必须以分号结尾,
原则上,必须书写这些分号。

但是为了方便起见,在某些情况下,分号可以省略,
ECMAScript会使用自动插入分号机制(Automatic Semicolon Insertion),
将省略的分号插入到源代码中。

2. 自动分号插入规则

自动分号插入机制,包含以下三条规则,以及两个例外情况。

2.1 规则

(1)由于源代码是从左到右解析的,所以如果一个token不满足已有的任何文法(grammar),且满足以下条件,那么就在这个token前面插入一个分号。
这个token,通常被称为offending token。

a) 该offending token与它之前的token被至少一个LineTerminator分隔。
b) 该offending token是}
c) 该offending token前面的token是),且插入分号后,
之前的语句可以被解析为do-whiledo Statement while (Expression) ;

(2)当读到token流结束标记的时候,如果整个token流无法解析成一个起始非终结符(goal nonterminal / goal symbol / start symbol),则会在末尾插入一个分号。

(3)即使一个token符合文法中的某个产生式,也可能会在它前面自动插入分号。
这种情况出现在受限产生式(restricted production)中,
受限产生式指的是包含[no LineTerminator here]字样的产生式,例如,

ReturnStatement :
    return;
    return [no LineTerminator here] Expression ;

如果一个token出现在受限产生式中[no LineTerminator here]的后面,且与前面的token被至少一个LineTerminator分隔,就会在该token前面插入分号。
这个token,通常被称为restricted token。

2.2 例外

在满足前三条规则的情况下,有两个例外。
(1)如果插入的分号,被解释为空语句,则不插入分号。
(2)由于for语句的头部包含两个分号,如果插入的分号会变成这两个分号中的任何一个,则不插入分号。

3. 所有的受限产生式

UpdateExpression :
    LeftHandSideExpression [no LineTerminator here] ++
    LeftHandSideExpression [no LineTerminator here] --

ContinueStatement :
    continue ;
    continue [no LineTerminator here] LabelIdentifier ;

BreakStatement :
    break;
    break [no LineTerminator here] LabelIdentifier ;

ReturnStatement :
    return;
    return [no LineTerminator here] Expression ;

ThrowStatement :
    throw [no LineTerminator here] Expression ;

ArrowFunction :
    ArrowParameters [no LineTerminator here] => ConciseBody

YieldExpression :
    yield [no LineTerminator here] *AssignmentExpression
    yield [no LineTerminator here] AssignmentExpression

在实际编程时,受限产生式对我们具有以下指导意义:
(1)如果++--需要被作为后缀运算符解析的时候,它们前面就不能出现LineTerminator,否则++--之前会被自动插入分号。
因此,++--后缀运算符,应该与它们的操作数在同一行。

(2)如果continuebreakreturnthrowyield后面出现了LineTerminator,那么它们后面会被自动插入分号。
因此,returnthrowyield,应该与后面的表达式在同一行,breakcontinue后面的label标签,应该和它们在同一行。

4. 例子

(1){ 1 2 } 3不是一个合法的ECMAScript字符串,即使通过自动插入分号。
但是,下面字符串经过自动插入分号,就变成了合法的字符串,

{ 1
2 } 3
{ 1
;2 ;} 3;

(2)以下字符串不合法,且无法自动插入分号,
因为自动插入的分号,不能成为for语句头部中的那两个分号之一。

for (a; b
)

(3)以下字符串会通过自动插入分号,变成两条语句。
因此,a + b并不会作为返回值被return

return
a + b
return;
a + b;

(4)以下字符串,会自动插入分号,使得++变成前缀运算符。

a = b
++c
a = b;
++c;

(5)以下字符串不合法,不是因为自动插入分号后,其后的else c = d不合法。
而是因为,自动插入的分号被解析成了空语句,因此就不能插入分号。

if (a > b)
else c = d

(6)以下字符串,不会自动插入分号,
因为第二行的(,将被解析为函数调用的左括号。

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

如果一个赋值语句必须以左括号开头(其他语句很少不得不以左括号开头),
最佳实践就是,显式的在该语句前的行尾加一个分号,而不是依赖自动分号插入机制。


参考

ECMAScript 2017 Language Specification
11.9 Automatic Semicolon Insertion
5.1.1 Context-Free Grammars
Wikipedia: Context-free grammar
Is "goal symbol" the same thing as "start symbol" in context-free-grammar

相关文章

  • [ECMAScript] 自动分号插入机制

    1. 插入分号 ECMAScript中,大部分声明和语句,都必须以分号结尾,原则上,必须书写这些分号。 但是为了方...

  • ASI(自动分号插入机制)和前置分号

    基本规则 以换行为基础,解析器会尽量将新行并入当前行,仅当符合ASI规则时才会将新行视为独立的语句。 ASI规则 ...

  • javaScript 基础

    初学JavaScript基础 ASI 自动分号插入(ASI)的目标是使分号对行结束来来说是可选的。引入自动分号插入...

  • javascript ASI(automatic semicol

    javascript ASI 就是指的是javascript的自动插入分号机制,就是说有的人写js的时候,其实是不...

  • 重学前端——语法

    分号 1. 自动插入分号规则(1)有换行符,且下一个符号是不符合语法的,自动插入分号;(2)有换行符,且语法中规定...

  • 06丨到底要不要写分号呢?

    自动插入分号规则 自动插入分号规则其实独立于所有的语法产生式定义,它的规则说起来非常简单,只有三条。 要有换行符,...

  • Airbnb规范

    不使用分号 使用分号 为什么? 当 JavaScript 遇到没有分号的换行符时,它使用一组称为自动分号插入的规则...

  • JS自动分号插入 ASI

    自动分号插入 (ASI),被认为是 JavaScript 中较为有争议的特征。 ASI 的规则是相对简单的:正如 ...

  • JS-为什么说添加分号是一个好习惯

    JavaScript在解析代码的时候并不是每行都添加分号的,自动分号插入(ASI)是JavaScript解析器添加...

  • no LineTerminator here

    自动插入分号规则 要有换行符,且下一个符号是不符合语法的,那么就尝试插入分号 有换行符, 且语法中规定此处不能有换...

网友评论

    本文标题:[ECMAScript] 自动分号插入机制

    本文链接:https://www.haomeiwen.com/subject/fmveuxtx.html