The evaluation process of a compound expression containing two assignment operators in JavaScript

188 views Asked by At

Here is a compound expression containing two assignment operators:

var a = {n: 1};
var b = a;
a.x = a = {m: 2};
a;    // => {m: 2}
b;    // => {n: 1, x: {m: 2}}

The tricky part is the third line:

a.x = a = {m: 2};

IMHO, The assignment operator = is right-associative, so the nesting structure of the expression is:

a.x = (a = {m: 2});

But the evaluation order in ES5 is always from left to right, according to ES5 Annex D.

According to ES5 Section 11.13.1,

The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:

  1. Let lref be the result of evaluating LeftHandSideExpression.
  2. Let rref be the result of evaluating AssignmentExpression.
  3. Let rval be GetValue(rref).
  4. Throw a SyntaxError exception if the following conditions are all true: ....omitted intentionally to save space
  5. PutValue(lref, rval).
  6. Return rval.

So my understanding of the left-to-right evaluation order is :

  1. evaluate a.x first and return a reference lref1 for it
  2. evaluate a = {m: 2} to obtain rref1, because it is also an assignment expression, we'll start the procedure again (like recursion)

    2.1. evaluate a first and return a reference lref2 for it

    2.2. evaluate {m: 2} and return the very object {m: 2} as rref2

    2.3. Let rval2 = GetValue(rref2), so rval2 is also the object {m: 2}

    2.4. PutValue(lref2, rval2), so a will rebinds the object {m: 2} instead of {n: 1}

    2.5. return rval2, i.e. the object {m: 2} as rref1 (not Reference type, but object)

  3. Let rval1 = GetValue(rref1), which is also the very object {m: 2}

  4. PutValue(lref1, rval1), so the memory address which lref1 refers to will be {m: 2}. And b.x still refers to this address and b will be updated.

This procedure complies to the ES5 Spec and explains the result well.

My questions are:

  1. Is this evaluation order abovementioned true or false? If false, any alternative explanations?

  2. How to understand the Reference Specification Type in ES5 appropriately? Is it just an intermediate pointer which refers to certain memory address?

1

There are 1 answers

5
apsillers On BEST ANSWER

Yes, your understanding about the operator order appears to be correct.

ECMAScript 5 section 8.7 says:

A Reference consists of three components, the base value, the referenced name and the Boolean valued strict reference flag. The base value is either undefined, an Object, a Boolean, a String, a Number, or an environment record (10.2.1).

The process of creating a reference from property access is defined in 11.2.1:

  1. Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.

Thus the reference lref1 holds the object value of a (along with the referenced name string "x"), which you originally created with {n: 1}. A reference does not care about the variable that it came from; it cares only about what base value and reference name it is supplied when created.

Altering what value is held by a has no effect whatsoever on the base value held by the reference lref1. lref1 continues to the hold the original value of a (i.e., that {n: 1} object) regardless of what a does after the creation of lref1.

In short, the reference created from the expression a.x ceases to have anything to do with the variable a as soon as the reference is created. Instead, the reference knows only about the value that was held by a at the time the reference was created.