Может кто-нибудь объяснить, как работают арифметические выражения javascript?
Давайте оценим этот код для замены двух переменных:
var a = 5, b = 3;
a = ( a -( b = ( a = a+b ) - b ) );
Я ожидал, что новое значение a
должно быть 3
и значение b
должно быть 5
, Но я получил значения как a = 0 and b = 5
;
Я прочитал арифметическое выражение EcmaScript и обнаружил, что оно будет оцениваться слева направо. (но не совсем понятно).
Так что я попробовал этот
var a = 5, b = 3;
a = ( ( b = ( a = a+b ) - b ) - a );
Теперь я получил a = -3 and b = 5
, Может кто-нибудь объяснить мне, почему это происходит так?
5 ответов
Как вы сказали, выражение вычисляется слева направо, то есть при первом обнаружении a его значение по-прежнему равно 5. Это сводится к:
var a = 5, b = 3;
a = ( a -( b = ( a = a+b ) - b ) );
a = 5 - (b = (a=(5+3)) - b);
a = 5 - (b = 8 - b);
a = 5 - 5; AND b = 5
Во втором значение a оценивается после присваивания, потому что оно справа
var a = 5, b = 3;
a = ( ( b = ( a = a+b ) - b ) - a );
a = ( ( b = 8 - b ) - a ); AND a = 8
a = ( 5 - 8 ); AND a = 8; AND b = 5;
a = - 3;
Все сводится к порядку оценки операндов.
Обычно в первом случае а оценивается до 5, затем b = ( a = a+b ) - b
оценивается, и только во время этой оценки значение изменяется, но не переносится.
Во втором примере ( b = ( a = a+b ) - b )
сначала оценивается, изменяя значение на 8, затем оценивается и получается 8
Более тривиальный пример:
var a = 5
a = a + (a = 2)
// a = 7
a
оценивается до 5, то (a = 2)
оценивается в 2, а устанавливается в 2, затем 5+2
оценивается и устанавливается на 7.
С другой стороны:
var a = 5
a = (a = 2) + a
// a = 4
(a = 2)
оценивается в 2, а устанавливается в 2, затем a
оценивается до 2, то 2+2
оценивается и устанавливается на 4
Вот объяснение, надеюсь, оно понятно, потому что оно не так очевидно. JS и все другие языки создают дерево для оценки выражений. Дерево назначает вес каждому оператору в зависимости от их положения и фигурных скобок.
Во-первых, вот шаги, которые JS обработает выражение:
Step 0. a = ( a - ( b = ( a = a+b ) - b ) ); a=5, b=3
Step 1. a = a+b a=8, b=3
Step 2. b = a - b a=8, b=5
Step 3. a = a - b a=0, b=5
На каждом шаге обрабатывает один оператор.
И это дерево, которое оно создает из вашего выражения:
=
/ \
a -
/ \
a =
/ \
b -
/ \
= b
/ \
a +
/ \
a b
Затем дерево обрабатывается снизу вверх.
var a = 5, b = 3;
a = ( ( b = ( a = a+b ) - b ) - a );
Это будет работать таким образом.
a = a + b //8
b = a - b //8-3=5
a = b - a //5-8=-3
a = ( a -( b = ( a = a+b ) - b ) )
похоже на это
a = ( 5 -( b = ( a = 5+3 ) - 3 ) ) // a = 8
// a = ( 5 - ( b = 8 - 3 ) ) // b = 5
// a = ( 5 - 5 ) // a = 0
Это означает, что он заменит a и b в левой части = за один раз с теми же начальными значениями, это не похоже на эту последовательность
a = a+b; // a = 8
b = a-b; // b = 5
a = a-b; // a = 3
как вы ожидаете.
var a = 5, b = 3;
a = ( a -( b = ( a = a+b ) - b ) );
1) a = a(5) - (остаток выражения, где в ближайшее время будут вычислены 2 части)
2) b = (a = a + b // и он все еще не рассчитан) - b (что равно 3, потому что новый b еще не изменен)
3) а = 5 (а) + 3(б) = 8
4) b (мы возвращаемся к пункту 2) = 8(новый a) - 3 (старый b) = 5
5) a (точка 1) = 5(старая a) - 5 (новая b) = 0
Новый а = 0, новый б = 5
var a = 5, b = 3;
a = ( ( b = ( a = a+b ) - b ) - a );
1) b = (a = a + b) - 3 (b)
2) а = 5 (а) + 3(б) = 8
3) b = 8 (новый a) - 3 (старый b) = 5
4) а (окончательный) = 5 (новый б) - 8 (новый а) = -3
Новый а = -3, новый б = 5
Я надеюсь, что это читабельно:D