最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript Ternary Operator lvalue - Stack Overflow

programmeradmin3浏览0评论

I was reading about the ternary operator in different languages, and noticed something interesting in the Javascript section. /%3F:#JavaScript

The conditional operator in JavaScript has the same syntax and precedence structure as in the other BCPL-derived variants, but a significant difference exists in the semantics: it returns an l-value.

The first sentence states that the return of the ternary in javascript is an lvalue, so I tried some examples, with odd results (in the chrome console).

Given:

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

Why does the first work and the second fail? (Logically they're the same statements, no?)

I was reading about the ternary operator in different languages, and noticed something interesting in the Javascript section. http://en.wikipedia.org/wiki/%3F:#JavaScript

The conditional operator in JavaScript has the same syntax and precedence structure as in the other BCPL-derived variants, but a significant difference exists in the semantics: it returns an l-value.

The first sentence states that the return of the ternary in javascript is an lvalue, so I tried some examples, with odd results (in the chrome console).

Given:

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

Why does the first work and the second fail? (Logically they're the same statements, no?)

Share Improve this question edited Sep 7, 2013 at 1:10 John Kugelman 362k69 gold badges548 silver badges594 bronze badges asked Sep 7, 2013 at 0:51 Ryan DignardRyan Dignard 6691 gold badge5 silver badges16 bronze badges 5
  • 1 Could the folks answering the question please cite sources that show Wikipedia's l-value statement is wrong? All of the answers so far are missing the point that l-value is by definition something that can be assigned to. – John Kugelman Commented Sep 7, 2013 at 1:00
  • To clarify, an l-value is a value that can be assigned to. The opposite of an l-value is an r-value, which can't be assigned to. The ternary operator returns an r-value in most languages, which is why the OP is asking about Wikipedia's unusual claim that it returns an l-value in JavaScript. – John Kugelman Commented Sep 7, 2013 at 1:04
  • 3 ECMA-262 is available online, and the conditional operator is covered in section 11.12 therein. Not once does it say "lvalue". Some Wikipedian probably got confused because the grammar calls the true and false branches AssignmentExpression -- but what that means is that the expression is allowed to be an assignment, so things like (condition) ? a = b : c = d work without syntactic contortions like (a = b, b). – cHao Commented Sep 7, 2013 at 1:11
  • @cHao Care to post that as an answer? – John Kugelman Commented Sep 7, 2013 at 1:16
  • @JohnKugelman: If i hadn't gone out to get something to eat, i'd consider it. :) As of now, though, the answer i'd write up wouldn't be all that different from the one Qantas wrote. – cHao Commented Sep 7, 2013 at 3:03
Add a comment  | 

5 Answers 5

Reset to default 6

Nope (it seems that Wikipedia's reference to "l-value" is misleading) - it is returning the value of the argument, not the reference to it; values in JavaScript cannot be assigned to directly1.

If you just did the following:

console.log(bool ? a.yo : b.yo);
// like doing the following:
'string' = 'eee';

... you would get a string - you can't assign to a string value/literal. All property references are converted to their value when passed into the conditional operator.

However, with an object, the reference value is an object, and since the property of an object is a reference, it works fine.

console.log(bool ? a : b); // you get an object, it's fine

The ECMAScript specification (that's the standard version of JavaScript) says that you can't get references (i.e. a l-value) from the conditional operator:

11.12 Conditional Operator ( ? : )

  1. Let lref be the result of evaluating LogicalORExpression.
  2. If ToBoolean(GetValue(lref)) is true, then:
    • Let trueRef be the result of evaluating the first AssignmentExpression.
    • Return GetValue(trueRef).
  3. Else
    • Let falseRef be the result of evaluating the second AssignmentExpression.
    • Return GetValue(falseRef).

GetValue is an internal function that converts a reference to a value, therefore that's why you get a value, not a reference as you expected.

1: The internal assignment method in ECMAScript does not allow non-references to be assigned to:

8.7.2 PutValue (V, W)

  1. If Type(V) is not Reference, throw a ReferenceError exception.
  2. ... (the rest is unimportant, my emphasis)

Wikipedia was wrong. The conditional operator returns an r-value, not an l-value.

The history of the article is quite interesting, so I've summarised it here:

  • 30 August 2010: The Beginning
    JavaScript section created. Correctly says that in JavaScript the ternary operator returns an r-value, but incorrectly says that in C/C++/Java it returns an l-value. Only in C++ the ternary operator returns an l-value.

  • 31 January 2011: Cannot yield an l-value in C
    C correctly removed from the JavaScript section because it doesn't return an l-value. Java remains.

  • 15 February 2011: "Corrected"
    The comparison to Java and C++ is removed (the comment correctly says that Java never yielded an l-value), but oh no! JavaScript suddenly returns an l-value!

  • 7 March 2011: Hope is restored...
    The incorrect "l-value" is changed to "value", linking to the Value article (which describes both l-values and r-values).

  • 7 March 2011: ...but not for long
    The link text is changed to say "l-value".

  • 7 September 2013: Three cheers for Qantas 94 Heavy!
    Thanks to this question, Wikipedia has been corrected.

Because the second line is not referencing the value of a.yo or b.yo, its referencing a flat object.

The first expression ends with .yo so it knows to reference the value of either a or b.

Has to do with how the js is actually implemented i guess... But consider this.. (bool ? a: b) give a so the code becomes a.yo = 'LLJ', which is valid.. (bool ? a.yo : b.yo) gives what ever the string a.yo is holding. Essentially you're doing 'moma' = 'LLJ' which is invalid.

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.

发布评论

评论列表(0)

  1. 暂无评论