I want to do something to a couple of variables using operators in quick succession. I don\'t think what I want to do is important as such; my question is more about th
According to ECMA-262 5th ed. 11.13.2,Compound Assignment Operators are evaluated as below:
- Let lref be the result of evaluating LeftHandSideExpression.
- Let lval be GetValue(lref).
- Let rref be the result of evaluating AssignmentExpression.
- Let rval be GetValue(rref).
- Let r be the result of applying operator @ to lval and rval.
- Throw a SyntaxError exception if the following conditions are all true: Type(lref) is Reference is true IsStrictReference(lref) is true Type(GetBase(lref)) is Environment Record
GetReferencedName(lref) is either "eval" or "arguments"- Call PutValue(lref, r).
- Return r.
The last example is evaluated as below:
1. Let a be lref, Let (b += (a += b)) be rlef.
2. Evaluate a and Let lval be the result of it(9).
3. Evaluate (b += (a += b)) and Let rval be the result of it.
a. Let b be lref_, Let (a += b) be rlef_.
b. Evaluate b and let lval_ be the result of it(2).
c. Evaluate (a += b) and let rval_ be the result of it.
A. Let a be lref__, let b be rlef.
B. Evaluate a and Let lval__ be the result of it(9).
C. Evaluate b and Let rval__ be the result of it(2).
D. Put lval__ + rval__ (means 9+2) to lref__(a) and return it.
d. Put lval_ + rval_ (means 2+11) to lref_(b) and return it.
4. Put lval + rval (means 9+13) to lref(a) and return it.
then we can get a === 22
, b === 13
.
I think (not sure, although this is counter-intuitive) you can imagine:
a += (b += (a += b));
being written as:
a = a + (b += (a += b));
Although the plus +
operator has right to left associativity, JavaScript expressions are evaluated from left-to-right, so a
is evaluated first which is 9
now, then (b += (a += b))
is evaluated to 13
.
Now the +
operator adds from right-to-left, thus adding 13
to 9
and giving us 22
.
EDIT: I am not gonna comment directly on your questions because I feel confused by reading them :).
Instead I am gonna try to explain this differently. I think the main source of your confusion comes from the difference between operator precedence, associativity and order of evaluation.
I really advise you to read the part on the Order of Evaluation (4.7.7 in the book, which is a great book by the way).
Let's go with an example first:
var x =1, y = 2, z = 3;
var alpha = (z=4) + y * z;
console.log(x); // 1
console.log(y); // 2
console.log(z); // 4
console.log(alpha); // 12
In this example, although the multiplication operator *
has higher precedence than the summation operator +
, the the evaluation of the different components of the entire expression is still from left-to-right.
alpha
on the left is declared and created first, then (z=4)
is evaluated, then y
is evaluated to 2
. Now z
is evaluated again which results in 4
, notice that this is the new value which is caused by the side-effect of assigning 4
to z
earlier in the expression, remember (z=4)
.
This results in an overall value for alpha
that is equal to 12
.
Now back to our original expression:
a += (b += (a += b));
a
on the left is evaluated first which is 9
now, then the first b
to the left is evaluated which is now 2
, now the second a
is evaluated which is 9
also, then the last b
to the right is evaluated which is again 2
.
Now starts the real work, because of the parentheses the last (a += b)
is evaluated so now we have a = 11
, then (b += (a += b))
is evaluated which is now 13
, now this value is summed the value already evaluated which is 9 resulting in 22
.
If it hasn't happened this way, this would mean that a
on the left side of =
would have been evaluated twice which is not the case.
Summary: You can't update the value of an already evaluated expression.
I hope this can clear this for you, if you have any further questions then feel free to ask :)