Каковы правила автоматической вставки точек с запятой в JavaScript (ASI)? - PullRequest
362 голосов
/ 17 мая 2010

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

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

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

return
  _a+b;

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

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

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

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

Ответы [ 4 ]

393 голосов
/ 17 мая 2010

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

  • пустая выписка
  • var выписка
  • выражение выражение
  • do-while выписка
  • continue выписка
  • break выписка
  • return выписка
  • throw выписка

Конкретные правила ASI, описаны в спецификации , раздел 11.9.1 Правила автоматической вставки точек с запятой

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

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

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

    например

    { 1
    2 } 3
    

    преобразуется в

    { 1
    ;2 ;} 3;
    

    NumericLiteral 1 соответствует первому условию, следующий токен является ограничителем строки.
    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";
    
40 голосов
/ 17 мая 2010

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

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

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

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

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

33 голосов
/ 27 января 2016

Я не мог понять эти 3 правила в спецификациях - надеюсь, у меня будет что-то более простое - но вот что я взял из JavaScript: Полное руководство, 6-е издание, Дэвид Фланаган, О'Рейли 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
};
17 голосов
/ 19 октября 2011

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

    var srcRecords = src.records
        srcIds = [];

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...