Правила автоматической вставки точек с запятой (ASI) в JavaScript
Здравствуйте. Сначала мне, вероятно, стоит уточнить, связана ли проблема с конкретным браузером.
Я читал, что если встречается недопустимый токен, но до этого момента код валиден, то перед недопустимым токеном будет вставлен точка с запятой, если перед ним стоит перенос строки.
Однако, распространённый пример, приводимый для иллюстрации ошибок, вызванных вставкой точки с запятой, выглядит так:
return
_a+b;
..что, похоже, не соответствует этому правилу, поскольку _a является допустимым токеном.
С другой стороны, разбиение цепочек вызовов работает, как и ожидалось:
$('#myButton')
.click(function(){alert("Hello!")});
Есть ли у кого-либо более подробное описание этих правил?
2 ответ(ов)
Я тоже не совсем понял эти три правила в спецификации — надеюсь, что смогу объяснить это более простым языком. Вот что я собрал из книги "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
};
Вопрос, касающийся вставки точек с запятой и оператора var
, предупреждает о том, что при использовании var
на нескольких строках можно случайно забыть запятую. Вот пример, который кто-то нашёл в моём коде вчера:
var srcRecords = src.records
srcIds = [];
Код сработал, но в результате объявление и присваивание srcIds
стало глобальным, так как локальное определение с помощью var
на предыдущей строке перестало действовать. Это произошло потому, что завершающая конструкция была автоматически воспринята как завершённая из-за вставки точки с запятой. Будьте внимательны при написании многострочных выражений с var
, чтобы избежать неожиданных глобальных переменных. В таких случаях лучше использовать запятую для разделения объявлений или располагать каждое объявление var
на отдельной строке.
Как перенаправить на другую веб-страницу?
Где найти документацию по форматированию даты в JavaScript?
Как определить нажатие клавиши Esc?
Как проверить, содержит ли массив строку в TypeScript?
Ссылка и выполнение внешнего JavaScript-файла, размещенного на GitHub