Может кто-нибудь объяснить, как работают арифметические выражения 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

Другие вопросы по тегам