提问者:小点点

JavaScript自动插入分号(ASI)的规则是什么?


好吧,首先我应该问一下这是否依赖于浏览器。

我读到过,如果发现一个无效的令牌,但该代码段在该无效令牌之前是有效的,如果该令牌前面有换行符,则会在该令牌之前插入分号。

但是,对于分号插入导致的bug,引用的常见例子是:

return
  _a+b;

。。它似乎不遵循这个规则,因为_a将是一个有效的标记。

另一方面,打破呼叫链如预期的那样起作用:

$('#myButton')
  .click(function(){alert("Hello!")});

有人对规则有更深入的描述吗?


共3个答案

匿名用户

首先,您应该知道哪些语句受自动插入分号(为简洁起见,也称为ASI)的影响:

  • 空语句
  • var语句
  • 表达式语句
  • do-while语句
  • continue语句
  • break语句
  • 返回语句
  • 抛出语句

ASI的具体规则见规范§11.9.1自动分号插入规则

本文介绍了三种情况:

  1. 遇到语法不允许的违规令牌时,如果:
  2. ,则在其前面插入分号
  • 令牌至少由一个LineTerminator与上一个令牌隔开。
  • 内标识为}

例如:

    { 1
    2 } 3

转换为

    { 1
    ;2 ;} 3;

NumericLiteral1满足第一个条件,下面的标记是行终止符。
2满足第二个条件,下面的标记是}

例如:

    a = b
    ++c

转换为:

    a = b;
    ++c;

限制生产:

    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

典型的例子是ReturnStatement:

    return 
      "something";

转换为

    return;
      "something";

匿名用户

我不能很好地理解规范中的这3条规则--希望有一些更简单的英语--但下面是我从JavaScript:最终指南,第6版,David Flanagan,O'Reilly,2011年收集到的内容:

报价:

JavaScript并不把每个换行符都当作分号来处理:它通常只在无法解析没有分号的代码时才把换行符当作分号来处理。

另一个引语:对于代码

var a
a
=
3 console.log(a)

JavaScript不把第二个换行符当作分号,因为它可以继续解析较长的语句a=3;

和:

当JavaScript无法将第二行解析为第一行语句的延续时,它将换行符解释为分号这一一般规则的两个例外。第一个异常涉及return,break和continue语句

。。。如果在这些单词后面出现换行符。。。JavaScript总是将该换行符解释为分号。

。。。第二个异常涉及到++和−−运算符。。。如果要将这两个运算符中的任何一个用作后缀运算符,它们必须与它们应用的表达式出现在同一行。否则,换行符将被视为分号,++或--将被解析为应用于后面代码的前缀运算符。考虑以下代码,例如:

x 
++ 
y

它被解析为x;++Y;,不作为x++;Y

所以我想简化一下,这意味着:

通常,只要有意义,JavaScript就会将其视为代码的延续--除了两种情况:(1)在一些关键字(如returnbreakcontinue)之后,以及(2)如果在新行上看到++--,那么它就会在前一行的末尾添加

关于“只要有意义就把它当作代码的延续”的部分让人感觉像是正则表达式的贪婪匹配。

根据以上所述,这意味着对于返回和换行符,JavaScript解释器将插入一个

(再次引用:如果在这些单词[如return]后出现换行符。。。JavaScript将始终将该换行符解释为分号)

由于这个原因,经典的例子

return
{ 
  foo: 1
}

不会按预期工作,因为JavaScript解释器将其视为:

return;   // returning nothing
{
  foo: 1
}

return:

return { 
  foo: 1
}

才能正常工作。如果要遵循在任何语句后使用的规则,您可以自己插入:

return { 
  foo: 1
};

匿名用户

直接来自ECMA-262第五版ECMAScript规范:

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

  • 当程序从左到右解析时,遇到任何语法生成都不允许的令牌(称为违规令牌)时,如果以下一个或多个条件为真,则会在违规令牌前自动插入分号:
    • 至少由一个LineTerminator将有问题的令牌与前一个令牌分隔。
    • 有问题的内标识为}

    但是,在前面的规则上还有一个附加的重写条件:如果分号随后被解析为空语句,或者该分号成为for语句标题中的两个分号之一,则从不自动插入分号(参见12.6.3)。