Каковы правила автоматической установки точки с запятой JavaScript (ASI)?
Ну, сначала я, вероятно, должен спросить, зависит ли это от браузера.
Я читал, что если найден недействительный токен, но раздел кода действителен до этого недопустимого токена, точка с запятой вставлена перед токеном, если ему предшествует разрыв строки.
Однако общий пример, приведенный для ошибок, вызванных вводом с запятой, следующий:
return
_a+b;
.. который, похоже, не следует этому правилу, так как _a будет действительным токеном.
С другой стороны, разрыв цепочек вызовов работает как ожидалось:
$('#myButton')
.click(function(){alert("Hello!")});
Есть ли у кого-нибудь более подробное описание правил?
Ответы
Ответ 1
Прежде всего, вы должны знать, на какие утверждения влияет автоматическая вставка точки с запятой (также известная как ASI для краткости):
- пустой оператор
- инструкция
var
- выражение выражения
- выражение
do-while
-
continue
выражение - оператор
break
-
return
statement -
throw
выражение
Конкретные правила ASI описаны в спецификации §11.9.1. Правила автоматической вставки точки с запятой
Описаны три случая:
-
Когда встречается токен (LineTerminator
или }
), который не разрешен грамматикой, точка с запятой вставлена перед ним, если:
- Маркер отделен от предыдущего токена, по крайней мере, одним
LineTerminator
. - Токен
}
например:
{ 1
2 } 3
трансформируется в
{ 1
;2 ;} 3;
NumericLiteral
1
соответствует первому условию, следующий токен - это терминатор линии.
2
соответствует второму условию, следующий токен }
.
-
Когда встречается конец входного потока токенов, и синтаксический анализатор не может проанализировать поток входных токенов как одну полную программу, то точка с запятой автоматически вставлена в конец входного потока.
например:
a = b
++c
преобразуется в:
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";
трансформируется в
return;
"something";
Ответ 2
Прямо от ECMA-262, пятое издание Спецификация ECMAScript:
7.9.1 Правила автоматической вставки точки с запятой
Существует три основных правила вставки точки с запятой:
- Когда, когда программа анализируется слева направо, появляется токен (называемый оскорбительным токеном), который не разрешен никаким производством грамматики, затем точка с запятой автоматически вставлена перед оскорбительным токеном, если один или несколько из следующих условий:
- Оскорбительный токен отделен от предыдущего токена хотя бы одним
LineTerminator
. - Оскорбительный токен }.
- Когда, когда программа анализируется слева направо, встречается конец входного потока токенов, и синтаксический анализатор не может проанализировать поток входных токенов как один полный ECMAScript
Program
, тогда точка с запятой автоматически вставленный в конец входного потока. - Когда, когда программа анализируется слева направо, встречается токен, допускаемый некоторой производством грамматики, но производство является ограниченным производством, а токен будет первым токеном для терминала или нетерминала сразу после аннотации " [no
LineTerminator
здесь]" в рамках ограниченного производства (и поэтому такой токен называется ограниченным токеном), а ограниченный токен отделен от предыдущего токена хотя бы одним LineTerminator, то точка с запятой автоматически вставлена перед ограниченным токеном.
Тем не менее, существует дополнительное условие переопределения для предыдущих правил: точка с запятой никогда не вставлена автоматически, если точка с запятой затем анализируется как пустой оператор или если эта точка с запятой станет одной из двух точек с запятой в заголовке a for (см. 12.6.3).
Ответ 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 будет рассматривать его как продолжение кода, если это имеет смысл, за исключением двух случаев: (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
};
Ответ 4
Что касается вставки точки с запятой и оператора var, остерегайтесь забывать запятую при использовании var, но охватывая несколько строк. Кто-то нашел это в моем коде вчера:
var srcRecords = src.records
srcIds = [];
Он выполнялся, но эффект заключался в том, что объявление/назначение srcIds было глобальным, потому что локальное объявление с var в предыдущей строке больше не применялось, поскольку этот оператор считался законченным из-за автоматической вставки вставки с двумя запятыми.
Ответ 5
Самое контекстное описание автоматической вставки точек с запятой в JavaScript, которое я нашел, взято из книги о крафт-интерпретаторах.
Правило "автоматической вставки точек с запятой" в JavaScripts является нечетным. Если в других языках предполагается, что большинство новых строк имеют смысл, а в многострочных операторах следует игнорировать лишь несколько, JS предполагает обратное. Он обрабатывает все ваши переводы строк как бессмысленные пробелы, если только он не сталкивается с ошибкой разбора. Если это так, он возвращается и пытается превратить предыдущий символ новой строки в точку с запятой, чтобы получить что-то грамматически правильное.
Он продолжает описывать это так, как вы бы кодировали запах.
Эта заметка о дизайне превратилась бы в конструкторскую диатрибу, если бы я подробно рассказал о том, как это вообще работает, и тем более о том, что это плохая идея. Это беспорядок. JavaScript - единственный язык, который я знаю, когда многие руководства по стилю требуют явных точек с запятой после каждого оператора, хотя язык теоретически позволяет вам их исключить.