6

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

13

Здравствуйте. Сначала мне, вероятно, стоит уточнить, связана ли проблема с конкретным браузером.

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

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

return
  _a+b;

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

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

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

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

2 ответ(ов)

0

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

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

С учетом вышеизложенного, если стоит return с переносом строки, интерпретатор JavaScript вставит ;

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

Из-за этого классический пример

return
{ 
  foo: 1
}

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

return;   // возвращает ничего
{
  foo: 1
}

Перенос строки не должен стоять сразу после return:

return { 
  foo: 1
}

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

return { 
  foo: 1
};
0

Вопрос, касающийся вставки точек с запятой и оператора var, предупреждает о том, что при использовании var на нескольких строках можно случайно забыть запятую. Вот пример, который кто-то нашёл в моём коде вчера:

var srcRecords = src.records
    srcIds = [];

Код сработал, но в результате объявление и присваивание srcIds стало глобальным, так как локальное определение с помощью var на предыдущей строке перестало действовать. Это произошло потому, что завершающая конструкция была автоматически воспринята как завершённая из-за вставки точки с запятой. Будьте внимательны при написании многострочных выражений с var, чтобы избежать неожиданных глобальных переменных. В таких случаях лучше использовать запятую для разделения объявлений или располагать каждое объявление var на отдельной строке.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь