GOT*_*O 0 7 javascript java syntax operator-precedence
这个Javascript表达式在所有浏览器中运行得很好(jsfiddle):
false ? 1 : x = 2;
Run Code Online (Sandbox Code Playgroud)
它正在评估2.
但为什么?我希望这里有一个例外,因为赋值的左边是false ? 1 : x,它不是有效的引用.与(jsfiddle)比较:
(false ? 1 : x) = 2;
Run Code Online (Sandbox Code Playgroud)
这个是扔了一个ReferenceError.我仔细检查了Javascript运算符优先级表,它声明条件运算符的? :优先级高于赋值运算符=,因此两个表达式应该相同,至少我是这样.
在Java中,它具有非常相似的语法和运算符优先级规则,如Javascript,上面的两个表达式都会导致编译时错误,这非常有意义.
有人可以解释这种差异吗?
nnn*_*nnn 14
正如您在MDN中发现的那样,? :具有比赋值运算符更高的优先级=,这意味着JS正在读取您的语句:
false ? 1 : (x = 2);
Run Code Online (Sandbox Code Playgroud)
乍一看,这似乎是倒退,但它的意思是? :期望三个操作数,其中右边的部分:是第三个操作数.由于=优先级较低,因此x = 2成为第三个操作数.
警报显示,2因为赋值x = 2将x变量设置为2,然后此(子)表达式求值为2.
你的第二个版本:
(false ? 1 : x) = 2;
Run Code Online (Sandbox Code Playgroud)
...给出一个引用错误,因为它(false ? 1 : x)首先执行部分计算与 x(undefined)相关联的值,它不返回变量x本身.undefined = 2不起作用.
以下是理解JavaScript条件表达式和Java条件表达式之间差异的两个关键:
请仔细阅读注意事项,在ECMAScript的5注释规范的这个部分的底部:
现在,请阅读条件表达式的Java规范部分:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25
您将注意到,正如ECMAScript 5注释所述,Java中三元运算符中的第三个操作数不能只是任何旧表达式 - 它只能是ConditionalExpression.但是,对于ECMAScript 5,第三个操作数可以是任何AssignmentExpression.
进一步看Java规范,我们看到Expression是任何赋值表达式:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.27
但是ConditionalExpression要么是带有三元运算符的ConditionalExpression(......?...:...),要么只是ConditionalOrExression(在ES5中称为LogicalOrExpression)(请参阅上面前两个链接中的任意一个信息).ConditionalOrExpression可以在Java中从这里开始的"链":
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.24
在ECMAScript 5中:
在ECMAScript 5规范中向后跟随表达式类型的"链"(因为它比Java规范更容易遵循)从ConditionalExpression开始,一直到基本上每个其他表达式,但是Assignment Expression最终将我们放在开头 - Primary Expression:
上面两个代码片段中的第二个操作数是一个主要表达式:
1
Run Code Online (Sandbox Code Playgroud)
所有这些rigamarole(如果我是正确的)的结果是在Java中,三元运算符的第三个操作数不能是赋值,但在JavaScript中它可以.这就是为什么你的两个例子都在Java中失败但在JavaScript中只是第二个.
为什么第一个工作在JavaScript而不是第二个?
operand1 ? operand2 : operand3;
Run Code Online (Sandbox Code Playgroud)
工作像下面IIFE代码(未实际,但下面的代码是说明性的在上述的工作原理):
(function () { if (operand0) return operand1; else return operand2;}());
Run Code Online (Sandbox Code Playgroud)
所以:
false ? 1 : x = 2;
Run Code Online (Sandbox Code Playgroud)
成为(再次,实际上不是- 下面的代码说明了上面的代码):
(function () { if (false) return 1; else return x = 2;}());
Run Code Online (Sandbox Code Playgroud)
但是,在您的第二个片段中,当使用parens时,您明确地将条件表达式与'= 2;'分开:
(false ? 1 : x) = 2;
Run Code Online (Sandbox Code Playgroud)
成为(再次,实际上不是- 下面的代码说明了上面的代码):
(function () { if (false) return 1; else return x;}()) = 2;
Run Code Online (Sandbox Code Playgroud)
三元运算符的"行为类似于示例IIFE函数调用"行为将返回x是什么,并且将是一个值,而不是一个无法分配的引用.因此错误.这将类似于以下代码(如果x === 3):
3 = 2;
Run Code Online (Sandbox Code Playgroud)
显然,人们不能这样做.
在Java中,我相信,第一个给出错误,因为第三个操作符不能是赋值,第二个给出错误,因为你不能赋值(就像在JavaScript中一样).
至于运营商优先级,请查看以下代码:
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"
Run Code Online (Sandbox Code Playgroud)
当根据上述IIFE说明性代码查看时,前两个容易理解.
在第一行中,x被计算,条件表达式的计算结果为3 - 这很容易.
在第二行中,我可以描述它的最好方法是条件运算符(?:)导致甚至较低优先级'='运算符被计算为完整表达式而不是因为(?:)具有更高的优先级,但是因为as规范声明评估':'后面的赋值表达式(包括'= 2'部分)作为AssignmentExpression.在上面的IIFE示例的return语句中,此行为看起来更清晰.至少使用JavaScript,您不仅可以在第二个操作数中进行赋值,还可以在条件表达式的第三个中进行赋值.
但是,在第三行中,已经在"x = 2"表达式中找到了完整的赋值表达式,并且三元运算符将其用作完整的第三个操作数,并且','运算符的优先级低于任何其他运算符,我们得到相当于以下代码:
console.log((false ? 1 : x = 2), 4);
Run Code Online (Sandbox Code Playgroud)
在第四行代码中,将整个表达式封装在parens中的console.log()语句中,将',4'作为第三个操作数的一部分引入'?:'三元表达式.
以下jsfiddles使用实时代码演示了上述讨论.请注意,在打印"2"两次后,前两个具有相同的确切错误:
三元运算符(?)需要三个值:条件,if-true和if-false.
在表达中
false ? 1 : x = 2
Run Code Online (Sandbox Code Playgroud)
编译器将false视为条件,1视为if-true且x = 2.既然?优先于= x尚未评估x = 2.所以,因为假性本质上是假的,所以x = 2就是返回的.
当评估x = 2时返回2.
为什么你可以写
x = y = 2
Run Code Online (Sandbox Code Playgroud)
在此示例中,x和y都设置为2.
整个x = 2被视为if-false操作数而不仅仅是x的原因是因为三元运算符将所有内容都放在以下的右边:if if-false如果它在范围内.
当你使用括号时,你要做的是将文字(无论x是什么)设置为2,从而导致错误.
我无法回答为什么在javascript中它可以工作的问题,但它导致java中的错误.我只能假设运营商优先级略有不同?
| 归档时间: |
|
| 查看次数: |
1083 次 |
| 最近记录: |