Почему эта запятая внутри тернарного оператора выдает синтаксическую ошибку в JavaScript?
Я заметил что-то странное при попытке использовать оператор запятой внутри условного (троичного) оператора для ведения журнала. Вот надуманный пример:
const a = 2;
const b = 1;
a > b ? console.log(a), a : b; //I expect this to log and evaluate to a
но вместо этого я встречаюсь с этим:
Uncaught SyntaxError: Unexpected token ,
по словам документация MDN, условный оператор принимает два выражения как случаи " if " и "else" тернарного оператора и оператор запятая теоретически - это выражение as,
оператор "запятая" вычисляет каждый из своих операндов (слева направо) и возвращает значение второго операнда.
так почему я получаю синтаксическую ошибку? Оператор запятой-это выражение, которое должно быть разрешено в условном операторе. Хотя, поставив скобки вокруг операндов запятой, отлично работает:
a > b ? (console.log(a), a) : b; //Logs and gives a
Почему это работает нормально? Скобки (или группировка оператор) позволяет интерпретатору знаю он имеет дело с выражением, но console.log(a), a
is уже выражение без скобок, так почему я получаю синтаксическую ошибку без них?
2 ответов
это намеренная часть языка и изложена в Спецификация Языка ECMAScript. Синтаксис оператора запятой определяется в 12.16, в которой говорится следующее:
12.16 Оператор Запятая ( , )
синтаксис
Expression: AssignmentExpression Expression, AssignmentExpression
здесь спецификация описывает, как использовать оператор запятая. Ан Expression
любой AssignmentExpression
или сам следовал с запятой (оператор) и другой AssignmentExpression
. Важно отметить, что AssignmentExpression
это Expression
но Expression
is не an AssignmentExpression
.
что касается фактического условного оператора, грамматика для оператора и условных выражений указана в 12.14:
12.14 условное Оператор (? : )
синтаксис
ConditionalExpression: LogicalORExpression LogicalORExpression ? AssignmentExpression : AssignmentExpression
в спецификации, условное выражение может содержать только AssignmentExpression
s -- не просто Expression
s. Таким образом, условный оператор не может иметь оператор запятой внутри одного из своих операндов. Это может показаться странной причудой языка, но есть определенная причина, учитывая очень специфическую грамматику, и в соответствии со спецификацией:
Примечание. Этот грамматика для
ConditionalExpression
в ECMAScript немного отличается от того, что в C и Java, каждый из которых позволит второе подвыражение бытьExpression
1 но ограничьте третье выражениеConditionalExpression
. мотивация этой разницы в ECMAScript заключается в том, чтобы разрешить выражение присваивания управляться любым плечом условного и to исключите запутанный и довольно бесполезный случай выражения запятой в качестве центрального выражения.
из-за ограничительной грамматики Java и C они не разрешают такие вещи (Java):
int a = 2;
int b = 1;
System.out.println(a > b ? b = a : a = b); //Can't use assignment in 'else' part
// ^^^^^
авторы ECMAScript решили разрешить присвоение в обеих ветвях тернарного оператора, таким образом, это определение с AssignmentExpression
произошла. Следовательно, это определение также запрещает оператору запятой фактически отображаться в "если" - часть условного оператора, но из-за его нехватки и бесполезности это не было проблемой. Они, по сути, убили двух зайцев одним выстрелом; допустили более мягкую грамматику и избавились от бесполезного синтаксиса, что является плохой практикой.
причина, по которой добавление оператора группировки позволяет ему работать, заключается в том, что производство оператора группировки ( Expression )
по определению также AssignmentExpression
позволяя ему находиться в тернарном операторе, см. ответ str для получения более подробной информации.
1 это относится к в Java Expression
, а не ECMAScript Expression
. В Java нет не у оператора запятой так его Expression
не включает его.
этот ответ подразумевается как расширение Li357 это. В частности, чтобы показать, где в грамматике условный оператор позволяет PrimaryExpression
s (который не включает оператор запятой), но не Expression
s (который включает оператор запятой).
см. ссылки на спецификацию для каждого упомянутого типа выражения или оператора в нижней части этого ответа.
спецификация условного Оператор определяется следующим образом:
ConditionalExpression: LogicalORExpression LogicalORExpression ? AssignmentExpression : AssignmentExpression
таким образом, это может быть либо LogicalORExpression
только, или сочетание LogicalORExpression
и два AssignmentExpression
s. Ан AssignmentExpression
сам может, среди прочего, быть указан LogicalORExpression
как хорошо.
но в отличие от его простого звучащего имени,LogicalORExpression
это не просто основное условие, но может состоять из многих, многих различных вложенных выражений.
Вплоть до PrimaryExpression
, который также включает сгруппированные выражения (Expression)
.
и как видно из спецификации оператора запятой, он указан только в Expression
, но не .
Expression: AssignmentExpression Expression , AssignmentExpression
чтобы суммировать его в более простых словах: грамматика JavaScript позволяет оператору запятой только в AssignmentExpression
если он содержится в операторе группировки ()
.
Смотрите также приоритет оператора в В JavaScript.