10

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

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

4

5 回答 5

6

不(似乎维基百科对“l-value”的引用具有误导性)——它返回的是参数的,而不是对它的引用;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 的标准版本)说您不能从条件运算符获取引用(即左值):

11.12 条件运算符(? : )

  1. lref是评估 LogicalORExpression 的结果。
  2. 如果ToBoolean(GetValue(lref))是真的,那么:
    • trueRef是评估第一个 AssignmentExpression 的结果。
    • 返回GetValue(trueRef)
  3. 别的
    • falseRef是评估第二个 AssignmentExpression 的结果。
    • 返回GetValue(falseRef)

GetValue是一个将引用转换为值的内部函数,因此这就是您获得值的原因,而不是您期望的引用。

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

8.7.2 看跌值(V,W)

  1. 如果Type(V)不是 Reference,则抛出 ReferenceError 异常
  2. ...(其余的不重要,我强调)
于 2013-09-07T00:55:39.273 回答
4

维基百科错了。条件运算符返回一个r-value,而不是一个l-value

这篇文章的历史很有趣,所以我在这里总结了一下:

  • 2010 年 8 月 30 日:创建了开始
    JavaScript 部分。正确地说在 JavaScript 中三元运算符返回一个 r 值,但错误地说在 C/C++/Java 中它返回一个左值。只有在 C++ 中,三元运算符才返回左值。

  • 2011 年 1 月 31 日无法
    从 JavaScript 部分正确删除 C 中的左值,因为它不返回左值。Java 仍然存在。

  • 2011 年 2 月 15 日“更正”
    删除了与 Java 和 C++ 的比较(评论正确地说 Java 从未产生左值),但是哦,不!JavaScript 突然返回一个左值!

  • 2011 年 3 月 7 日希望恢复...
    不正确的“l-value”更改为“value”,链接到Value 文章(描述 l-values 和 r-values)。

  • 2011 年 3 月 7 日...但时间不长
    链接文本更改为“l-value”。

  • 2013 年 9 月 7 日为 Qantas 94 Heavy 欢呼三声!
    感谢这个问题,维基百科得到了更正。

于 2013-09-07T02:20:31.657 回答
3

因为第二行没有引用a.yoor的值b.yo,所以它引用了一个平面对象。

第一个表达式以 结尾,.yo因此它知道要引用aor的值b

于 2013-09-07T00:55:32.140 回答
1

我猜这与js的实际实现方式有关......但是考虑一下这个......(bool?a:b)给a所以代码变成a.yo ='LLJ',这是有效的......(bool?a .yo : b.yo) 给出字符串 a.yo 所持有的内容。本质上你在做 'moma' = 'LLJ' 这是无效的。

于 2013-09-07T00:58:28.137 回答
1

Here d becomes your set variable.

    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);

The reason the code didn't work would be the same reason you can't replace dummyFn's value with obj. Without a property to reference the object becomes anonymous.

于 2013-09-07T02:07:00.777 回答