我正在阅读不同语言的三元运算符,并注意到Javascript部分中有趣的内容。 http://en.wikipedia.org/wiki/%3F:#JavaScript
JavaScript中的条件运算符具有与其他BCPL派生变体相同的语法和优先级结构,但语义中存在显着差异:它返回l-value。
第一句话说javascript中三元的返回值是左值,所以我尝试了一些例子,结果很奇怪(在chrome控制台中)。
假设:
var a = { 'yo' : 'momma' }
var b = { 'yo' : 'cool' }
var bool = true
(bool? a : b).yo = 'LLJ'
//a is now { 'yo' : 'LLJ' }
(bool? a.yo : b.yo) = 'LLJ' //throws a reference error
为什么第一次工作而第二次失败? (逻辑上它们是相同的陈述,不是吗?)
答案 0 :(得分:6)
Nope(似乎维基百科对“l值”的引用具有误导性) - 它返回参数的值,而不是引用; JavaScript中的值不能直接分配给 1 。
如果您刚刚执行了以下操作:
console.log(bool ? a.yo : b.yo);
// like doing the following:
'string' = 'eee';
...你会得到一个字符串 - 你不能分配给字符串值/文字。传递给条件运算符时,所有属性引用都将转换为它们的值。
但是,对于一个对象,引用值是一个对象,并且由于对象的属性是引用,它可以正常工作。
console.log(bool ? a : b); // you get an object, it's fine
ECMAScript规范(这是JavaScript的标准版本)表示您无法从条件运算符获取引用(即l值):
11.12 Conditional Operator(?:)
- 让
lref
成为评估LogicalORExpression的结果。- 如果
ToBoolean(GetValue(lref))
为真,那么:
- 让
trueRef
成为评估第一个AssignmentExpression的结果。- 返回
GetValue(trueRef)
。- 否则
醇>
- 让
falseRef
成为评估第二个AssignmentExpression的结果。- 返回
GetValue(falseRef)
。
GetValue
是一个将引用转换为值的内部函数,因此这就是为什么你得到一个值,而不是你期望的引用。
1: ECMAScript中的内部分配方法不允许将非引用分配给:
8.7.2 PutValue(V,W)
- 如果
Type(V)
不是引用,抛出ReferenceError异常。- ......(其余的不重要,我的重点)
醇>
答案 1 :(得分:3)
维基百科错了。条件运算符返回 r值,而不是 l值。
这篇文章的历史非常有趣,所以我在这里总结一下:
30 August 2010:开始
JavaScript部分已创建。正确地说,在JavaScript中,三元运算符返回一个r值,但错误地说在C / C ++ / Java中它返回一个l值。只有在C ++中,三元运算符才会返回一个l值。
31 January 2011:无法在C中产生l值
C正确地从JavaScript部分删除,因为它不返回l值。 Java仍然存在。
15 February 2011:“已更正”
删除了与Java和C ++的比较(注释正确地说Java从未产生l值),但是哦不! JavaScript突然返回一个l值!
7 March 2011:希望恢复......
不正确的“l值”更改为“value”,链接到Value article(描述l值和r值)。
7 March 2011: ...但不会很久
链接文本更改为“l-value”。
7 September 2013: Qantas 94 Heavy的三次欢呼!
感谢这个问题,维基百科已得到纠正。
答案 2 :(得分:2)
因为第二行没有引用a.yo或b.yo的值,所以它引用了一个扁平对象。
第一个表达式以.yo结尾,因此它知道引用a或b的值。
答案 3 :(得分:1)
与猜测js实际实现的方式有关... 但考虑一下.. (bool?a:b)给出一个代码变成a.yo ='LLJ',这是有效的.. (bool?a.yo:b.yo)给出了a.yo所持有的字符串。基本上你在做 'moma'='LLJ'无效。
答案 4 :(得分:1)
这里d成为你的设定变量。
var obj = {'d' : 1, 'd1': 2}, obj2 = {'d': 2, 'd1': 2}, bool = true;
var dummyFn = function(obj, k, v) { obj['k'] = val; return obj; };
(bool ? (dummyFn(obj, 'd', (obj.d = newVal + 1))) : obj).d1 = newVal = 4;
console.log(obj.d);
代码不起作用的原因与您无法替换dummyFn的值的原因相同 与obj。没有属性来引用该对象变得匿名。