Javascript三元运算符左值

时间:2013-09-07 00:51:48

标签: javascript lvalue

我正在阅读不同语言的三元运算符,并注意到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

为什么第一次工作而第二次失败? (逻辑上它们是相同的陈述,不是吗?)

5 个答案:

答案 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(?:)

     
      
  1. lref成为评估LogicalORExpression的结果。
  2.   
  3. 如果ToBoolean(GetValue(lref))为真,那么:   
        
    • trueRef成为评估第一个AssignmentExpression的结果。
    •   
    • 返回GetValue(trueRef)
    •   
  4.   
  5. 否则   
        
    • falseRef成为评估第二个AssignmentExpression的结果。
    •   
    • 返回GetValue(falseRef)
    •   
  6.   

GetValue是一个将引用转换为值的内部函数,因此这就是为什么你得到一个值,而不是你期望的引用。

1: ECMAScript中的内部分配方法不允许将非引用分配给:

  

8.7.2 PutValue(V,W)

     
      
  1. 如果Type(V)不是引用,抛出ReferenceError异常
  2.   
  3. ......(其余的不重要,我的重点)
  4.   

答案 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。没有属性来引用该对象变得匿名。