Javascript Ternary Operator lvalue

Ryan Dignard picture Ryan Dignard · Sep 7, 2013 · Viewed 11.2k times · Source

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

Answer

Qantas 94 Heavy picture Qantas 94 Heavy · Sep 7, 2013

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)