There's an important difference between associativity and order of evaluation.
In JavaScript, even though the assignment operator groups right to left, the operands are evaluated left to right before the actual assignments are performed (which do occur right to left). Consider this example:
var a = {};
var b = {};
var c = a;
c.x = (function() { c = b; return 1; })();
The variable c
initially references a
, but the right-hand side of the assignment sets c
to b
. Which property gets assigned, a.x
or b.x
? The answer is a.x
because the left-hand side is evaluated first, when c
still references a
.
In general, the expression x = y
is evaluated as follows:
- Evaluate
x
and remember the result.
- Evaluate
y
and remember the result.
- Assign the result from step 2 to the result of step 1 (and return the former as the result of the expression
x = y
).
What happens with multiple assignments, as in x = (y = z)
? Recurse!
- Evaluate
x
and remember the result.
- Evaluate
y = z
and remember the result. To do this:
- Evaluate
y
and remember the result.
- Evaluate
z
and remember the result.
- Assign the result from step 2.2 to the result of step 2.1 (and return the former as the result of the expression
y = z
).
- Assign the result from step 2 to the result of step 1 (and return the former as the result of the expression
x = (y = z)
).
Now let's look at your example, slightly edited:
var foo = {};
var bar = foo; // save a reference to foo
foo.x = (foo = {a:1}); // add parentheses for clarity
foo.x
is evaluated before foo
gets assigned to {a:1}
, so the x
property gets added to the original {}
object (which you can verify by examining bar
).
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…