Почему эта запятая внутри тернарного оператора выдает синтаксическую ошибку в 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, каждый из которых позволит второе подвыражение быть Expression1 но ограничьте третье выражение 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 это. В частности, чтобы показать, где в грамматике условный оператор позволяет PrimaryExpressions (который не включает оператор запятой), но не Expressions (который включает оператор запятой).


см. ссылки на спецификацию для каждого упомянутого типа выражения или оператора в нижней части этого ответа.

спецификация условного Оператор определяется следующим образом:

ConditionalExpression:
  LogicalORExpression
  LogicalORExpression ? AssignmentExpression : AssignmentExpression

таким образом, это может быть либо LogicalORExpression только, или сочетание LogicalORExpression и два AssignmentExpressions. Ан AssignmentExpression сам может, среди прочего, быть указан LogicalORExpression как хорошо.

но в отличие от его простого звучащего имени,LogicalORExpression это не просто основное условие, но может состоять из многих, многих различных вложенных выражений. Вплоть до PrimaryExpression, который также включает сгруппированные выражения (Expression).

и как видно из спецификации оператора запятой, он указан только в Expression, но не .

Expression:
  AssignmentExpression
  Expression , AssignmentExpression

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

Смотрите также приоритет оператора в В JavaScript.

ресурсы