Каковы правила автоматической вставки точки с запятой (ASI) в JavaScript?

Ну, сначала я должен, вероятно, спросить, зависит ли это от браузера.

Я прочитал, что если найден недопустимый токен, но раздел кода действителен до этого недопустимого токена, точка с запятой вставляется перед токеном, если ему предшествует разрыв строки.

однако общим примером ошибок, вызванных вставкой точки с запятой, является:

return
  _a+b;

..который, похоже, не следует этому правилу, так как _a будет действительным знак.

С другой стороны, разрыв цепочек вызовов работает так, как ожидалось:

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

есть ли у кого-нибудь более подробное описание правил?

4 ответов


прежде всего, вы должны знать, на какие операторы влияет автоматическая вставка точки с запятой (также известная как ASI для краткости):

  • пустые заявления
  • var сообщении
  • выражение заявлением
  • do-while сообщении
  • continue сообщении
  • break сообщении
  • return сообщении
  • throw сообщении

бетон правила АСИ, описаны в спецификации §11.9.1 правила автоматической вставки точки с запятой

описаны три случая:

  1. когда токен (LineTerminator или }) встречается, что не допускается грамматикой, перед ней вставляется точка с запятой, если:

    • маркер отделен от предыдущего маркера по крайней мере одним LineTerminator.
    • маркер }

    например:

    { 1
    2 } 3
    

    превращается в

    { 1
    ;2 ;} 3;
    

    на NumericLiteral 1 соответствует первому условию, следующий токен является Терминатором строки.
    The 2 соответствует второму условию, следующий токен }.

  2. при обнаружении конца входного потока токенов и невозможности синтаксического анализа входного потока токенов как единого полного Программа, затем точка с запятой автоматически вставляется в конце входного потока.

    например:

    a = b
    ++c
    

    превращается в:

    a = b;
    ++c;
    
  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
    

    классический пример, с помощью тега ReturnStatement:

    return 
      "something";
    

    превращается в

    return;
      "something";
    

прямиком из ECMA-262, пятое издание ECMAScript спецификация:

7.9.1 правила автоматической вставки точки с запятой

существует три основных правила вставки точки с запятой:

  1. когда, как программа разбирается слева направо, токен (называется обидеть маркер) встречается, что не допускается каким-либо производством грамматики, то точка с запятой автоматически вставляется перед маркер-нарушитель, если выполняется одно или несколько из следующих условий:
    • оскорбительный токен отделен от предыдущего токена по крайней мере одним LineTerminator.
    • оскорбительный токен }.
  2. когда при разборе программы слева направо обнаруживается конец входного потока токенов, и синтаксический анализатор не может разобрать входной поток токенов как один полный ECMAScript Program, затем a точка с запятой автоматически вставляется в конец входного потока.
  3. когда при разборе программы слева направо встречается токен, который разрешен некоторым производством грамматики, но производство является ограниченного производства и токен будет первым токеном для терминала или нетерминала сразу после аннотации"[нет LineTerminator здесь]" в рамках ограниченного производства (и, следовательно, такой знак называется ограниченный токен), и ограниченный токен отделен от предыдущего токена по крайней мере одним LineTerminator, затем точка с запятой автоматически вставляется перед ограниченным маркером.

однако в предыдущих правилах есть дополнительное условие переопределения: точка с запятой никогда не вставляется автоматически, если точка с запятой будет затем проанализирована как пустой оператор или если эта точка с запятой станет одной из двух точек с запятой в заголовке на заявление (см. 12.6.3).


я не мог понять эти 3 правила в спецификациях слишком хорошо-надеюсь, что у вас будет что-то более простое на английском языке-но вот что я собрал из JavaScript: The Definitive Guide, 6th Edition, 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 будет рассматривать его как продолжение кода, пока это имеет смысл - за исключением 2 случаев: (1) после некоторых ключевых слов, таких как return, break, continue, и (2) если он видит ++ или -- в новой строке, затем он добавит ; в конце предыдущей строки.

часть о "рассматривать его как продолжение кода, пока это имеет смысл" заставляет его чувствовать себя жадным совпадением регулярного выражения.

С выше сказанным, это значит для return при разрыве строки интерпретатор JavaScript вставит ;

(снова процитировано: если после любого из этих слов появляется разрыв строки [например,return] ... JavaScript всегда будет интерпретировать эта строка прерывается точкой с запятой)

и по этой причине, классический пример

return
{ 
  foo: 1
}

не будет работать так, как ожидалось, потому что интерпретатор JavaScript будет рассматривать его как:

return;   // returning nothing
{
  foo: 1
}

должно быть разрыва строки сразу после return:

return { 
  foo: 1
}

для его правильной работы. И вы можете вставить ; себя, если вы должны были следовать правилу использования ; после любого заявлении:

return { 
  foo: 1
};

Что касается вставки точки с запятой и оператора var, остерегайтесь забывать запятую при использовании var, но охватывая несколько строк. Кто-то нашел это в моем коде вчера:

    var srcRecords = src.records
        srcIds = [];

он работал, но эффект состоял в том, что объявление/назначение srcIds было глобальным, потому что локальное объявление с var в предыдущей строке больше не применялось, поскольку этот оператор считался законченным из-за автоматической вставки с запятой.