Цепочка составных операторов присваивания в JavaScript

In C#,

string s = "abc";
s += (s += s);
Console.WriteLine(s);

пишет abcabcabc (http://ideone.com/pFNFX2). Это нормально, потому что спецификация C# прямо говорит в разделе 7.16.2, что

операция оценивается как x = x op y, за исключением того, что x оценивается только один раз.

Однако, читая описание составного оператора присваивания в разделе 11.3.2 Спецификации языка ECMAScript 5.1, я не вижу такого квалификатора «только один раз» в семантике этого оператора. Вместо этого я вижу только:

  1. Пусть lref будет результатом вычисления LeftHandSideExpression.
  2. Пусть lval будет GetValue(lref).
  3. Пусть rref будет результатом оценки AssignmentExpression.
  4. Пусть rval будет GetValue(rref).
  5. Пусть r будет результатом применения оператора @ к lval и rval.
  6. Вызовите исключение SyntaxError, если выполняются все следующие условия: (отрезано)
  7. Вызовите PutValue(lref, r).
  8. Возврат р.

Поэтому может показаться (во всяком случае мне), что следующий код JavaScript

var s = "abc";
s += (s += s);
alert(s);

будет предупреждать abcabcabcabc (из-за PutValue в строке 7 в выражении в скобках), но в любом случае в Chrome 22 он предупреждает abcabcabc.

Итак, мой вопрос: я неправильно понимаю спецификацию, или Chrome (возможно, V8?) делает что-то нестандартное, так сказать?


person Ray Toal    schedule 28.10.2012    source источник
comment
Вы тестировали в любом другом браузере, чтобы убедиться, что это поведение такое же?   -  person Ian    schedule 28.10.2012
comment
Если вы разберете, что на самом деле представляет собой s += (s += s);, оно станет s = s + (s + s);, и я думаю, что это достаточно просто, чтобы сказать, что результат должен быть abcabcabc   -  person Ian    schedule 28.10.2012
comment
Почему это переписано именно так? Почему бы нам не переписать и полностью не оценить сначала правую часть и... О... ах! Я думаю, у вас есть ответ.   -  person Ray Toal    schedule 28.10.2012


Ответы (1)


Поэтому я думаю, что если вы откроете операцию, у вас будет:

s += (s += s);

s = s + (s += s);
s = s + (s = s + s);    // Can't actually have the "s = " part, it's really just "s + s"
s = s + (s + s);
s = s + s + s;

Это означает, что результатом должно быть «abcabcabc».

person Ian    schedule 28.10.2012
comment
Вот и все. Ключевой является строка 2 в семантике. Он преобразует s в lval еще до того, как мы взглянем на правую часть. Вы хорошо отразили это в своем расстройстве. - person Ray Toal; 28.10.2012