JavaScript的自动分号插入(ASI)有哪些规则?

那么,首先我应该问问这是否依赖于浏览器。

我读过如果找到无效标记,但代码段直到该无​​效标记才有效,则在标记之前插入分号(如果它前面有换行符)。

但是,引用由分号插入引起的错误的常见示例是:

return
  _a+b;

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

另一方面,打破呼叫连锁按预期工作:

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

有没有人有更深入的规则描述?


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

  • 空的陈述
  • var语句
  • 表达声明
  • do-while声明
  • continue声明
  • break声明
  • return语句
  • throw声明
  • 规范中描述了ASI的具体规则:

  • §11.9.1自动分号插入规则
  • 描述了三种情况:

  • 遇到语法不允许的令牌( LineTerminator} )时,如果出现以下情况,则在其之前插入分号:

  • 令牌由至少一个LineTerminator与前一个令牌分开。
  • 令牌是}
  • 例如:

        { 1
        2 } 3
        // is transformed to
        { 1
        ;2 ;} 3;
    

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

  • 当遇到令牌输入流的末尾并且解析器无法将输入令牌流解析为单个完整的程序时,则会在输入流末尾自动插入分号。

    例如:

    a = b
    ++c
    // is transformed to:
    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";
    // is transformed to
    return;
      "something";
    

    直接从ECMA-262,第五版ECMAScript规范:

    7.9.1自动插入分号的规则

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

  • 当从左向右分析程序时,遇到任何语法产生都不允许的令牌(称为违规令牌),则在冒犯令牌之前自动插入分号,如果以下一项或多项条件是正确的:
  • 有问题的令牌与以前的令牌至少由一个LineTerminator分开。
  • 有问题的令牌是}。
  • 当从左向右分析程序时,会遇到令牌输入流的末尾,并且解析器无法将输入令牌流解析为单个完整的ECMAScript Program ,然后在分配结束时自动插入分号输入流。
  • 当程序从左到右被解析时,会遇到一些文法生成所允许的标记,但是生产是一个受限制的生产,并且该标记将是紧跟在注释后面的终端或非终结符的第一个标记“限制生产中的[这里没有LineTerminator ](因此这样一个标记被称为限制标记),受限制的标记与前一个标记至少被一个LineTerminator分开,然后在限制标记之前自动插入一个分号。
  • 但是,对于上述规则,还有一个额外的覆盖条件:如果分号会被分析为空语句或该分号将成为for语句头部中的两个分号之一,则从不自动插入分号(请参阅12.6.3)。


    我无法理解规范中的这3条规则 - 希望得到更简单的英语 - 但这里是我从JavaScript收集的内容:权威指南,第6版,David Flanagan,O'Reilly,2011:

    引用:

    JavaScript不会将每个换行符都当作分号来处理:它通常只会将换行符作为分号,除非它不能在没有分号的情况下解析代码。

    另一个引用:代码

    var a
    a
    =
    3 console.log(a)
    

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

    和:

    当解释第二行作为第一行语句的延续时,JavaScript将行解释为分号的一般规则有两个例外。 第一个例外涉及返回,中断和继续语句

    ...如果在这些单词之后出现换行符... JavaScript将始终将该换行符解释为分号。

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

    x 
    ++ 
    y
    

    它被解析为x; ++y; x; ++y; ,而不是x++; y x++; y

    所以我认为要简化它,这意味着:

    一般来说,只要有意义,JavaScript就会将其视为代码的延续 - 除了两种情况:(1)在某些关键字如returnbreakcontinue和(2)如果它看到++--之后新行,那么它会添加; 在上一行的结尾处。

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

    通过上述说法,这意味着用换行符return ,JavaScript解释器将插入一个;

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

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

    return
    { 
      foo: 1
    }
    

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

    return;   // returning nothing
    {
      foo: 1
    }
    

    return后不得立即return

    return { 
      foo: 1
    }
    

    为它正常工作。 你可以插入一个; 你自己如果你要遵循使用a的规则; 在任何声明之后:

    return { 
      foo: 1
    };
    
    链接地址: http://www.djcxy.com/p/51685.html

    上一篇: What are the rules for JavaScript's automatic semicolon insertion (ASI)?

    下一篇: Multiple variables in Python 'with' statement