简体   繁体   English

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

[英]Why does this comma inside a ternary operator throw a syntax error in JavaScript?

I noticed something odd when trying to use the comma operator inside the conditional (ternary) operator for logging. 当我尝试在条件(三元)运算符中使用逗号运算符进行日志记录时,我注意到了一些奇怪的事情。 Here's a contrived example: 这是一个人为的例子:

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

But instead I'm met with this: 但相反,我遇到了这个:

Uncaught SyntaxError: Unexpected token ,

According to the MDN documentation , the conditional operator accepts two expressions as the 'if' and 'else' cases of the ternary operator, and the comma operator theoretically is an expression as, 根据MDN文档 ,条件运算符接受两个表达式作为三元运算符的“if”和“else”情况,而逗号运算符理论上是表达式

The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand. 逗号运算符计算其每个操作数(从左到右)并返回最后一个操作数的值。

So why do I get a syntax error? 那我为什么会出现语法错误? The comma operator is an expression which should be allowed to be in a conditional operator. 逗号运算符是一个表达式,应该允许它在条件运算符中。 Although, putting parentheses around the comma's operands works fine: 虽然,在逗号的操作数周围加括号可以正常工作:

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

Why does that work fine? 为什么这样可行? Parentheses (or the grouping operator ) allows the interpreter to know it's dealing with an expression, but console.log(a), a is already an expression without the need of parentheses, so why do I get a syntax error without them? 括号(或分组运算符 )允许解释器知道它正在处理表达式,但是console.log(a), a 已经是一个表达式而不需要括号,那么为什么没有它们会出现语法错误?

This is an intentional part of the language, and is outlined in the ECMAScript Language Specification . 这是该语言的有意部分,并在ECMAScript语言规范中进行了概述。 The syntax for the comma operator is defined in Section 12.16 , which states the following: 逗号运算符的语法在第12.16节中定义,其中说明了以下内容:

12.16 Comma Operator ( , ) 12.16逗号运算符(,)

Syntax 句法

\nExpression: 表达:\n  AssignmentExpression AssignmentExpression\n  Expression, AssignmentExpression 表达,AssignmentExpression\n

Here, the specification outlines how the comma operator is used. 这里,规范概述了如何使用逗号运算符。 An Expression is any AssignmentExpression or itself followed with a comma (the operator) and another AssignmentExpression . Expression是任何AssignmentExpression或其自身后跟逗号(运算符)和另一个AssignmentExpression The important thing to note is that an AssignmentExpression is an Expression but an Expression is not an AssignmentExpression . 需要注意的重要一点是, AssignmentExpression是一个ExpressionExpression 不是 AssignmentExpression

As for the actual conditional operator, the grammar for the operator and conditional expressions is specificed in Section 12.14 : 对于实际的条件运算符,运算符和条件表达式的语法在12.14节中具体说明:

12.14 Conditional Operator ( ? : ) 12.14条件运算符(?:)

Syntax 句法

\nConditionalExpression : 条件表达式  \n  LogicalORExpression LogicalORExpression  \n  LogicalORExpression ? LogicalORExpression? AssignmentExpression : AssignmentExpression AssignmentExpression:AssignmentExpression\n

By the specification, a conditional expression can only contain AssignmentExpression s -- not just Expression s. 根据规范,条件表达式只能包含AssignmentExpression s - 而不仅仅是Expression s。 Thus a conditional operator cannot have a comma operator inside one of its operands. 因此,条件运算符不能在其操作数之一中包含逗号运算符。 This may seem like a weird quirk of language, but there is a specific reason considering the very specific grammar, and per the specification: 这可能看起来像一个奇怪的语言怪癖,但有一个特定的原因考虑非常具体的语法,并按照规范:

NOTE The grammar for a ConditionalExpression in ECMAScript is slightly different from that in C and Java , which each allow the second subexpression to be an Expression 1 but restrict the third expression to be a ConditionalExpression . 注意ECMAScript中ConditionalExpression的语法与C和Java中的语法略有不同,每个语法允许第二个子表达式为Expression 1,但将第三个表达式限制为ConditionalExpression The motivation for this difference in ECMAScript is to allow an assignment expression to be governed by either arm of a conditional and to eliminate the confusing and fairly useless case of a comma expression as the centre expression. ECMAScript中这种差异的动机是允许赋值表达式由条件的任一臂控制,消除逗号表达式作为中心表达式的混乱且相当无用的情况。

Because of Java and C's restrictive grammar, they do not allow things like this (Java): 由于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 authors decided to allow for assignment in both branches of the ternary operator, thus this definition with AssignmentExpression occurred. ECMAScript作者决定允许在三元运算符的两个分支中进行赋值,因此发生了AssignmentExpression这个定义。 Consequently, this definition also disallows for the comma operator to actually show up in the 'if' part of the conditional operator, but because of its scarcity and uselessness it wasn't a problem. 因此,这个定义也不允许逗号运算符实际显示在条件运算符的“if”部分,但由于它的稀缺性和无用性,它不是问题。 They essentially killed two birds with one stone; 他们基本上一石二鸟; allowed for more lenient grammar and got rid of useless syntax that's bad practice. 允许更宽松的语法,并摆脱无用的语法,这是不好的做法。

The reason why adding the grouping operator allows it to work is because the grouping operator production ( Expression ) is by definition also an AssignmentExpression allowing it to be in the ternary operator, see str's answer for more details. 添加分组运算符允许它工作的原因是因为分组运算符生成( Expression )根据定义也是一个AssignmentExpression允许它在三元运算符中,有关更多详细信息,请参阅str的答案


1 This refers to Java's Expression , not ECMAScript's Expression . 1这是指Java的Expression ,而不是ECMAScript的Expression Java's does not have the comma operator so its Expression does not include it. Java的没有逗号运算符所以其Expression不包括它。

This answer is meant as an extension of Li357's answer . 这个答案是Li357答案的延伸。 Specifically to show where in the grammar the Conditional Operator allows PrimaryExpression s (which does not include the Comma Operator) but not Expression s (which does include the Comma Operator). 具体来说,为了显示语法中的条件,条件运算符允许PrimaryExpression s(不包括逗号运算符)而不是Expression s(包括逗号运算符)。


Please see the links to the specification for every mentioned type of expression or operator on the bottom of this answer. 请参阅本答案底部每个提到的表达式或运算符的规范链接。

The specification of the Conditional Operator is defined as follows: 条件运算符的规范定义如下:

 ConditionalExpression: LogicalORExpression LogicalORExpression ? AssignmentExpression : AssignmentExpression 

Thus it can be either a LogicalORExpression only, or a combination of LogicalORExpression and two AssignmentExpression s. 因此,它既可以是LogicalORExpression ,也可以是LogicalORExpression和两个AssignmentExpression的组合。 An AssignmentExpression itself can, among other things, be specified by a LogicalORExpression as well. 除其他事项外, AssignmentExpression本身也可以由LogicalORExpression指定。

But unlike its simple sounding name, the LogicalORExpression is not just a basic condition but can consist of many, many different nested expressions itself. 但与其简单的声音名称不同, LogicalORExpression不仅仅是一个基本条件,而且可以由许多不同的嵌套表达式本身组成。 All the way down to PrimaryExpression which also includes grouped expressions (Expression) . 一直到PrimaryExpression ,其中还包括分组表达式(Expression)

And as can be seen in the specification of the Comma Operator, it is only specified in Expression , but not in PrimaryExpression itself. 从逗号运算符的规范中可以看出,它只在Expression指定,但在PrimaryExpression本身中没有指定。

 Expression: AssignmentExpression Expression , AssignmentExpression 

To summarize it in simpler words: The grammar of JavaScript only allows the comma operator within an AssignmentExpression if it is contained within a grouping operator () . 用简单的词汇总结一下:JavaScript的语法只允许在AssignmentExpression的逗号运算符,如果它包含在分组运算符()

Also see the Operator Precedence in JavaScript . 另请参阅JavaScript中运算符优先级

Resources 资源

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM