Подтвердить что ты не робот

Почему эта запятая внутри тернарного оператора выдает синтаксическую ошибку в JavaScript?

Я заметил что-то странное при попытке использовать оператор запятой внутри условного (тройного) оператора для ведения журнала. Здесь надуманный пример:

const a = 2;
const b = 1;
a > b ? console.log(a), a : b; //I expect this to log and evaluate to a
4b9b3361

Ответ 1

Это преднамеренная часть языка и описывается в Спецификация ECMAScript Language. Синтаксис для оператора запятой определяется в Раздел 12.16, в котором говорится следующее:

12.16 Comma Operator (,)

Синтаксис

Expression:
  AssignmentExpression
  Expression, AssignmentExpression

Здесь спецификация описывает, как используется оператор запятой. Expression - это любой AssignmentExpression или сам по себе с запятой (оператор) и другой AssignmentExpression. Важно отметить, что AssignmentExpression - это Expression, но Expression не a AssignmentExpression.

Что касается фактического условного оператора, то грамматика для оператора и условных выражений определяется в Раздел 12.14:

12.14 Условный оператор (?:)

Синтаксис

ConditionalExpression:  
  LogicalORExpression  
  LogicalORExpression ? AssignmentExpression : AssignmentExpression

По спецификации условное выражение может содержать только AssignmentExpression s - не только Expression s. Таким образом, условный оператор не может иметь запятый оператор внутри одного из своих операндов. Это может показаться странным причудом языка, но есть определенная причина, учитывающая очень специфическую грамматику и спецификацию:

ПРИМЕЧАНИЕ   Грамматика для ConditionalExpression в ECMAScript несколько отличается от грамматики в C и Java, каждая из которых позволяет второму подвыражению быть Expression 1 но ограничиваем третье выражение ConditionalExpression. Мотивация для этой разницы в ECMAScript заключается в том, чтобы позволить выражению присваивания управляться любым выражением условного и , чтобы устранить запутанный и довольно бесполезный случай выражения запятой в качестве центрального выражения.

Из-за строгой грамматики 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 произошло. Следовательно, это определение также запрещает, чтобы оператор-запятая фактически отображался в "if" части условного оператора, но из-за его скудности и бесполезности это не было проблемой. Они по сути убили двух зайцев одним камнем; допускал более мягкую грамматику и избавлялся от бесполезного синтаксиса, что плохой практикой.

Причина, по которой добавление оператора группировки позволяет ему работать, заключается в том, что производство оператора группировки ( Expression ) по определению также означает AssignmentExpression, позволяющее ему находиться в тройном операторе, см. str answer для более подробной информации.


1 Это относится к Java Expression, а не к ECMAScript Expression. Java не имеет оператор запятой, поэтому его Expression не включает.

Ответ 2

Этот ответ подразумевается как расширение ответа Li357. В частности, чтобы показать, где в грамматике Условный оператор допускает PrimaryExpression (который не включает Comma Operator), но не Expression (который включает в себя Comma Operator).


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

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

ConditionalExpression:
  LogicalORExpression
  LogicalORExpression ? AssignmentExpression : AssignmentExpression

Таким образом, это может быть либо только LogicalORExpression, либо комбинация LogicalORExpression и двух AssignmentExpression s. Сам AssignmentExpression может, помимо прочего, указываться как LogicalORExpression.

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

И как можно видеть в спецификации Comma Operator, он указан только в Expression, но не в PrimaryExpression.

Expression:
  AssignmentExpression
  Expression , AssignmentExpression

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

Также см. Приоритет оператора в JavaScript.

Ресурсы