简体   繁体   English

带条件和赋值运算符的表达式

[英]Expressions with conditional and assignment operator

This Javascript expression is working just fine in all browsers ( jsfiddle ): 这个Javascript表达式在所有浏览器( jsfiddle )中都可以正常工作:

false ? 1 : x = 2;

It's evaluating to 2. 评估为2。

But why? 但为什么? I'd expect an exception here, because the left hand side of the assignment is false ? 1 : x 我期望在这里出现异常,因为赋值的左侧是false ? 1 : x false ? 1 : x , which is not a valid reference. false ? 1 : x ,这不是有效的参考。 Compare with ( jsfiddle ): 与( jsfiddle )比较:

(false ? 1 : x) = 2;

This one is throwing a ReferenceError . 这是引发ReferenceError I double checked the Javascript operator precedence table , it states that the conditional operator ? : 我仔细检查了Javascript运算符优先级表 ,它指出条件运算符? : ? : has higher precedence than the assignment operator = , so both expressions should be identical, at least I though so. ? :优先级高于赋值运算符= ,因此两个表达式应该相同,至少我是这样。

In Java, which has pretty similar syntax and operator precedence rules like Javascript, both expressions above result in a compile time error, which makes perfectly sense. 在Java中,其语法和运算符优先级规则(例如Javascript)非常相似,而上述两个表达式均会导致编译时错误,这很有意义。

Can someone explain this difference? 有人可以解释这种差异吗?

As you found at MDN, ? : 如您在MDN所发现的, ? : ? : has a higher precendence than the assignment operator = , which means that JS is reading your statement as: ? :具有比赋值运算符=更高的优先级,这意味着JS会将您的声明读取为:

false ? 1 : (x = 2);

At first glance that might seem backwards, but what it means is that ? : 乍一看似乎是倒退,但这意味着什么? : ? : is expecting three operands, with the part on the right of the : being the third operand. ? :期望三个操作数, :右边的部分是第三个操作数。 Since = has lower precedence x = 2 becomes the third operand. 由于=优先级较低,因此x = 2成为第三个操作数。

The alert shows 2 because the assignment x = 2 sets the x variable to 2 and then this (sub)expression evaluates to 2 . 警报显示2因为赋值x = 2x变量设置为2 ,然后该(子)表达式的计算结果为2

Your second version: 您的第二个版本:

(false ? 1 : x) = 2;

...gives a reference error because it does the (false ? 1 : x) part first which evaluates to the value associated with x ( undefined ), it doesn't return the variable x itself. ...给出一个参考错误,因为它首先执行(false ? 1 : x)部分,该部分的计算结果与 xundefined相关联 ,它不返回变量x本身。 undefined = 2 doesn't work. undefined = 2不起作用。

Here are the two keys to understanding the difference between the JavaScript conditional expression and the Java conditional expression: 这是理解JavaScript条件表达式和Java条件表达式之间区别的两个关键:

Please read the Note at the bottom of this section of the ECMAScript 5 annotated specification: 请ECMAScript的5注释规范的这个部分的底部阅读注意事项

http://es5.github.io/#x11.12 http://es5.github.io/#x11.12

Now, please read the Java specification section for the conditional expression: 现在,请阅读Java规范部分中的条件表达式:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25 http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25

You will note that as the ECMAScript 5 note states, the third operand in the ternary operator in Java cannot be just any old expression - it can only be a ConditionalExpression. 您将注意到,正如ECMAScript 5注释所述, Java中三元运算符的第三个操作数不能只是任何旧表达式-只能是ConditionalExpression。 However, for ECMAScript 5, the third operand can be any AssignmentExpression. 但是,对于ECMAScript 5,第三个操作数可以是任何AssignmentExpression。

Looking further at the Java spec, we see that Expression is any assignment expression: 进一步查看Java规范,我们看到Expression是任何赋值表达式:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.27 http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.27

But ConditionalExpression is either the ConditionalExpression with the ternary operator (... ? ... : ...) or just a ConditionalOrExpression (termed LogicalOrExpression in ES5) (see either of the first two links above for that info). 但是ConditionalExpression要么是带有三元运算符(...?...:...)的ConditionalExpression,要么就是ConditionalOrExpression(在ES5中称为LogicalOrExpression)(有关该信息,请参见上面的前两个链接之一)。 The "chain" of what the ConditionalOrExpression can be starts here in Java: Java中的ConditionalOrExpression可以是什么的“链”从这里开始:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.24 http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.24

And here in ECMAScript 5: 在ECMAScript 5中:

http://es5.github.io/#x11.11 http://es5.github.io/#x11.11

Following the "chain" of expression types backward in the ECMAScript 5 spec (because it is easier to follow than the Java spec) from ConditionalExpression all the way through basically every other expression but Assignment Expression finally lands us at the beginning - Primary Expression: 从ConditionalExpression到ECMAScript 5规范中的表达式类型的“链”一直向后移动(因为比Java规范更容易遵循),基本上贯穿所有其他表达式,但赋值表达式最终使我们进入了开始-主表达式:

http://es5.github.io/#x11.1 http://es5.github.io/#x11.1

The second operand in both of your code snippets above is a primary expression: 上面两个代码段中的第二个操作数都是一个主要表达式:

1

The upshot of all this rigamarole (if I am correct) is that in Java, the third operand of the ternary operator cannot be an assignment, but in JavaScript it can. 所有这些rigamarole(如果我是对的话)的结果是,在Java中,三元运算符的第三个操作数不能是赋值,但在JavaScript中可以。 That is why both of your examples fail in Java but only the second in JavaScript. 这就是您的两个示例都在Java中失败而在JavaScript中仅第二个失败的原因。

Why does the first one work in JavaScript but not the second? 为什么第一个在JavaScript中起作用,而第二个却不起作用?

operand1 ? operand2 : operand3;

works like the following IIFE code (not actually , but the below code is illustrative of how the above works): 就像下面的IIFE代码一样工作( 实际上不是,但是下面的代码说明了上面的工作方式):

(function () { if (operand0) return operand1; else return operand2;}());

So: 所以:

false ? 1 : x = 2;

becomes (again, not actually - the below code is illustrative of the above code): 变成(再次, 实际上不是-下面的代码说明了上面的代码):

(function () { if (false) return 1; else return x = 2;}());

However, in your second snippet, when using the parens, you separate out explicitly the conditional expression from the ' = 2;': 但是,在第二个片段中,使用括号时,您将条件表达式与'= 2;'明确分开:

(false ? 1 : x) = 2;

becomes (again, not actually - the below code is illustrative of the above code): 变成(再次, 实际上不是-下面的代码说明了上面的代码):

(function () { if (false) return 1; else return x;}()) = 2;

The "acts like the example IIFE function invocation" behavior of the ternary operator will return whatever x is and that will be a value , not a reference, which cannot be assigned to. 三元运算符的“类似于IIFE函数调用示例的行为”行为将返回x,并且x将是一个 (而不是引用),该值不能被赋值。 Hence the error. 因此,错误。 This would be like the following code (if x === 3): 就像下面的代码(如果x === 3):

3 = 2;

Obviously, one cannot do this. 显然,不能做到这一点。

In Java, I believe, the first one gives an error because the third operator cannot be an assignment, the second one gives an error because you cannot assign to a value (just like in JavaScript). 我相信在Java中,第一个错误是因为第三个运算符不能是赋值,第二个错误是因为您不能赋值(就像JavaScript中一样)。

As far as operator precedence, please look at the following code: 至于运算符的优先级,请查看以下代码:

var x = 3;

console.log(false ? 1 : x);          // ?: evaluates to "3"
console.log(false ? 1 : x = 2);      // ?: evaluates to "2"
console.log(false ? 1 : x = 2, 4);   // ?: evaluates to "2" - "2" and "4" arguments passed to log
console.log((false ? 1 : x = 2, 4)); // ?: evaluates to "4"

The first two are easily understood when viewed in terms of the IIFE illustrative code above. 从上面的IIFE说明性代码来看,前两个很容易理解。

In the first line x is evaluated and the conditional expression evaluates to 3 - that's easy. 在第一行中,对x进行求值,条件表达式的求值为3-很简单。

In the second line, the best way I can describe it is that the conditional operator (?:) causes even the lower precedence '=' operator to be evaluated as a complete expression not because (?:) has higher precedence, but because as the spec states the assignment expression following the ':' is evaluated (including the ' = 2' part) as an AssignmentExpression. 在第二行中,我能描述的最好方法是条件运算符(?:)甚至将较低优先级的'='运算符都视为完整表达式,不是因为(?:)具有较高的优先级,而是因为规范指出了':'之后的赋值表达式被评估为包括AssignmentExpression(包括'= 2'部分)。 This behavior looks clearer in the return statement in the IIFE examples above. 在上面的IIFE示例的return语句中,此行为看起来更加清楚。 With JavaScript at least, you can have an assignment not only in the second operand but also the third of the conditional expression. 至少使用JavaScript,您不仅可以在第二个操作数中而且在条件表达式的第三个中都具有赋值。

However, in the third line, a complete assignment expression is already found in the "x = 2" expression and the ternary operator uses it as the complete third operand, and the ',' operator being lower in precedence than any other, we get the equivalent to the following code: 但是,在第三行中,已经在“ x = 2”表达式中找到了一个完整的赋值表达式,三元运算符将其用作完整的第三操作数,并且','运算符的优先级低于任何其他运算符,我们得到等效于以下代码:

console.log((false ? 1 : x = 2), 4);

In the fourth line of code, encapsulating the entire expression within the console.log() statement in parens brings the ', 4' into the '?:' ternary expression as part of the third operand. 在代码的第四行中,将整个表达式封装在parens的console.log()语句中,将“,4”放入“?:”三元表达式中,作为第三个操作数的一部分。

The following jsfiddles demonstrate the above discussion with live code. 以下jsfiddles使用实时代码演示了以上讨论。 Note that the first two have the same exact error after printing '2' twice: 请注意,两次打印“ 2”后,前两个具有相同的确切错误:

FIDDLE1 FIDDLE1

FIDDLE2 FIDDLE2

FIDDLE3 FIDDLE3

The ternary operator (?) needs three values: A condition , an if-true and an if-false . 三元运算符(?)需要三个值: 条件if-trueif-false

In the expression 在表达中

false ? 1 : x = 2

the compiler sees false as the condition, 1 as the if-true and x=2 . 编译器将false视为条件,将1视为if-true和x = 2 Since ? 因为? takes priority over = the x=2 has not yet been evaluated. 优先于= = x = 2尚未评估。 So since false is by nature false the x=2 is what is returned. 因此,由于false本质上是false,因此返回x = 2

When evaluated x=2 returns 2. 当评估为x = 2时,返回2。

Hence why you can write 因此,为什么你可以写

x = y = 2

In this example x and y are both set to 2. 在此示例中,x和y都设置为2。

The reason the whole x=2 is seen as the if-false operand and not just the x is because the ternary operator takes everything to the right of the : as the if-false if it is within scope. 将整个x = 2视为if-false操作数而不仅仅是x的原因是因为三元运算符将所有在:右边的内容作为if-false(如果它在范围内)。

When you use the brackets however what you are trying to do is set a literal (whatever x is) to 2, resulting in an error. 但是,当您使用方括号时,您想要做的是将文字(无论x是什么)设置为2,从而导致错误。

I can't answer the question of why in javascript it works whereas it results in an error in java however. 我无法回答为什么它在javascript中起作用而在Java中却导致错误的问题。 I can only assume slightly different operator priorities? 我只能假设操作员的优先级略有不同吗?

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

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