为什么三元运算符中的逗号会在JavaScript中引发语法错误?

时间:2017-12-31 01:15:41

标签: javascript ecmascript-6 syntax-error language-lawyer ternary-operator

当我尝试在条件(三元)运算符中使用逗号运算符进行日志记录时,我发现了一些奇怪的东西。这是一个人为的例子:

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 documentation,条件运算符接受两个表达式作为三元运算符的“if”和“else”情况,理论上comma operator 是表达式 as,

  

逗号运算符计算每个操作数(从左到右)并返回最后一个操作数的值。

那为什么我会出现语法错误?逗号运算符是一个表达式,应该允许它在条件运算符中。虽然,将括号括在逗号的操作数周围可以正常工作:

a > b ? (console.log(a), a) : b; //Logs and gives a

为什么这样可行?括号(或grouping operator)允许解释器知道它处理表达式,但console.log(a), a 表达式而不需要括号那么为什么没有它们会出现语法错误?

2 个答案:

答案 0 :(得分:29)

这是该语言的有意识部分,并在ECMAScript Language Specification中进行了概述。逗号运算符的语法在Section 12.16中定义,其中包含以下内容:

  

12.16逗号运算符(,)

     

语法

Expression:
  AssignmentExpression
  Expression, AssignmentExpression

此处,规范概述了如何使用逗号运算符。 Expression 是任何 AssignmentExpression 或其后跟一个逗号(运算符)和另一个 AssignmentExpression 。需要注意的重要一点是 AssignmentExpression Expression ,但 Expression 是< strong>不 AssignmentExpression

对于实际的条件运算符,运算符和条件表达式的语法在Section 12.14中具体说明:

  

12.14条件运算符(?:)

     

语法

ConditionalExpression:  
  LogicalORExpression  
  LogicalORExpression ? AssignmentExpression : AssignmentExpression

根据规范,条件表达式只能包含 AssignmentExpression s - 而不仅仅是 Expression 。因此,条件运算符不能在其操作数之一中包含逗号运算符。这可能看起来像一个奇怪的语言怪癖,但有一个特定的原因考虑非常具体的语法,并按照规范:

  

请注意   ECMAScript中 ConditionalExpression 的语法与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's answer

1 这是指 Java的Expression ,而不是ECMAScript的 Expression 。 Java的具有逗号运算符,因此 Expression 不包含它。

答案 1 :(得分:1)

这个答案是Li357's answer的延伸。具体来说,为了显示语法中的条件,条件运算符允许PrimaryExpression s(不包括逗号运算符)而不是Expression s(包括逗号运算符)。

请参阅本答案底部每个提到的表达式或运算符类型的规范链接。

条件运算符的规范定义如下:

ConditionalExpression:
  LogicalORExpression
  LogicalORExpression ? AssignmentExpression : AssignmentExpression

因此,它可以是仅LogicalORExpression,也可以是LogicalORExpression和两个AssignmentExpression的组合。除其他事项外,AssignmentExpression本身也可以由LogicalORExpression指定。

但与其简单的声音名称不同,LogicalORExpression不仅仅是一个基本条件,而且可以由许多不同的嵌套表达式组成。 一直到PrimaryExpression,其中还包括分组表达式(Expression)

从逗号运算符的规范中可以看出,它仅在Expression中指定,但在PrimaryExpression本身中未指定。

Expression:
  AssignmentExpression
  Expression , AssignmentExpression

用简单的词汇总结一下:如果逗号运算符包含在分组运算符AssignmentExpression中,则JavaScript的语法只允许()内的逗号运算符。

另见Operator Precedence in JavaScript

资源