Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Приоритеты в выражении запутали (https://javascript.ru/forum/misc/75218-prioritety-v-vyrazhenii-zaputali.html)

AlexanderFilatov 14.09.2018 08:57

Приоритеты в выражении запутали
 
Здравствуйте!Помогите понять, почему переменная c = 5?
Ведь сначала вычисляется выражение в скобках: (a = b), т.е. переменная a меняет свое
значение на 10.А после происходит взятие остатка: 15 % 10 = 5.Только я вот чего не могу уяснить, почему переменная a в левой части выражении равняется 15, а не 10!?Значение переменной a должно было изменится, после операции в скобках или видимо тут используется старое значение переменной a.Подскажите пожалуйста в чем ошибка в моих рассуждениях!И как вычисляется по приоритетам данное выражение!Заранее спасибо!
var a = 15, b = 10, c;
c = a % (a = b);
alert(c); // 5

Artur_Hopf 14.09.2018 09:10

AlexanderFilatov,
вот что у тебя происходит:
var a = 15, b = 10, c;
c = a /* "а" у тебя тут равно 15*/ % (a/* только тут у тебя "а" становится 10*/ = b);

// итого 15 % 10 = 5
alert(c); // 5

AlexanderFilatov 14.09.2018 09:29

Это я понял!Но ведь переменная a ссылается на одну область памяти и если у нее поменялось значение в одно месте, то и в другом должно поменяться!Почему так?

Artur_Hopf 14.09.2018 09:42

AlexanderFilatov,
Так первую "а" ты еще не успел поменять. Это в математика сначала скобки выполняются, а присваивание переменных это не математика. Все идет с лева на право, код у тебя читается так 15 % (10).

AlexanderFilatov 14.09.2018 10:00

Все сообразил!Я понял в чем ошибка моих размышлений!Я думал математически и забыл что интерпретатор вычисляет выражение слева направо!Большое спасибо за ответ!

laimas 14.09.2018 10:08

Цитата:

Сообщение от AlexanderFilatov
интерпретатор вычисляет выражение слева направо

Он руководствуется вложениями, скобками и приоритетами, просто он берет присвоенное значение переменной при расчетах. Можно было бы и без переменной "с", присвоив результат расчета "a".

А сначала он не считает, а производит лексический анализ написанного выражения, и только потом принимает решение о действиях.

AlexanderFilatov 14.09.2018 10:28

Цитата:

Сообщение от laimas
Он руководствуется вложениями

Что вы понимаете под вложениями?

Получается он подставляет сначала значение 15, а затем значение 10 вычислив выражение (a = b) и присваивает той же переменной вот так:
var a = 15, b = 10;
a = a % (a = b);
alert(a); // 5

Я правильно вас понял!?

laimas 14.09.2018 10:47

Цитата:

Сообщение от AlexanderFilatov
Что вы понимаете под вложениями?

Язык программирования не только же для расчетов дважды два, в нем могут быть сложные выражения. Интерпретатор разбирая в общем то простой текст, анализирует, что требуется выполнить. А выполнение выражения будет зависеть от приоритетов операций, скобок. выражение может содержать и вложенные действия. Если к примеру нужно выполнить функцию b, один из аргументов которой задан как выполнение функции a, то сначала будет выполнена функция а, и только потом функция b. То есть если схематично представить так:

выражение 1(выражение 2(выражение 3))

то порядок выполнения всего выражения будет с 3 к 1, а никак ни слева направо.

ksa 14.09.2018 11:33

Цитата:

Сообщение от AlexanderFilatov
Это я понял!Но ведь ...

Значит не до конца понял... :(

AlexanderFilatov 14.09.2018 12:06

Цитата:

Сообщение от laimas
Если к примеру нужно выполнить функцию b, один из аргументов которой задан как выполнение функции a, то сначала будет выполнена функция а, и только потом функция b. То есть если схематично представить так:

выражение 1(выражение 2(выражение 3))

Значит порядок выполнения в данном конкретном примере такой:
1.В "a" подставляется значение 15
2.Далее происходит вычисление выражения: (a = b), в переменную "a" получит значение переменной "b".(присвоение)То есть 10.
3. 15 % (10)
4.Результат 5 запишется снова в переменную "a".
Я правильно понял суть?

laimas 14.09.2018 12:21

Цитата:

Сообщение от AlexanderFilatov
Далее происходит вычисление выражения: (a = b), в переменную "a"

Здесь a = b просто бессмысленное действие, равноценно как проще (b), а так как и скобки тут не нужны, то все ваше действие упрощается до a % b. В левой части будет 15, а что там вы далее творите, может иметь значение, но не в данном случае.

А вот "Результат 5 запишется снова в переменную "a", это да и это конечное значение.

Ну это равноценно как написать в тетрадке в клеточку:

x = 2
y = 3

x * (y + 18)

Анализируем, получаем выражение:

2 * (3 + 18)

далее по правилам арифметики вычисляем то, что в скобках, а приравниваете ли вы результат этого вычисления чему либо в уме или нет, это не имеет для выражения никакого значения.

AlexanderFilatov 14.09.2018 13:00

Цитата:

Сообщение от laimas
Здесь a = b просто бессмысленное действие, равноценно как проще (b), а так как и скобки тут не нужны, то все ваше действие упрощается до a % b. В левой части будет 15, а что там вы далее творите, может иметь значение, но не в данном случае.

Здесь это понятно, что бессмысленно!Просто я разбирал одну из реализаций алгоритма Евклида:
function nod(a, b) {
        while (b !== 0) {
           b = a % (a = b);
        } 
        return a;
    }
alert(nod(21, 14));

И вот на этом примере я "завис"!Теперь все понял!Спасибо.

ksa 14.09.2018 13:04

Цитата:

Сообщение от AlexanderFilatov
Здесь это понятно, что бессмысленно!

Зачем тогда это применять на деле?
Дабы потом очередной бедняга не понимал откуда берется та пятерка?

Это все нидзя стайл.

AlexanderFilatov 14.09.2018 13:07

Цитата:

Сообщение от ksa
Зачем тогда это применять на деле?

Хотелось разобраться в сути!

ksa 14.09.2018 13:19

Цитата:

Сообщение от AlexanderFilatov
Хотелось разобраться в сути!

Есть прогеры, которые специально используют особенности ЯП дабы специально и максимально запутать код программы.
В том случае просто сэкономили на одной переменной и видал какой резонанс. :)

Мое мнение - не стоит так поступать.

laimas 14.09.2018 13:20

Цитата:

Сообщение от AlexanderFilatov
И вот на этом примере я "завис"!

Ну так ваш код с кодом этой функции нельзя сравнивать, вы просто воткнули увиденное себе без всякой пользы. А в функции присвоение переменной a значения переменной b используется в следующих итерациях, а также является возвращаемым значением. Просто выведите в консоль:

function nod(a, b) {
    while (b !== 0) {
        console.log('before '+a);
        b = a % (a = b);
        console.log('after '+a);
    }
    console.log('return '+a);
    return a;
}
nod(21, 14);


PS. Кстати, кроме приоритета операторы обладают еще и ассоциативностью.

AlexanderFilatov 17.09.2018 09:33

Ваш пример понятен.В режиме call stack chrome все значения переменных на каждом этапе цикла показывает!Про приоритеты и ассоциативность понятно.Поправьте меня если я не прав!Вообщем сначала интерпретатор проводит построчный анализ кода!(слева на право)А потом в соответствии с приоритетами и ассоциативностью вычисляет выражение.Вроде так!
Например здесь он сначала вычисляет значение в скобках, а потом использует новое значение переменной "a" при операции делении:
var b = 10, a = 5;
a = (a = b) / a;
alert(a); // 1

AlexanderFilatov 17.09.2018 10:49

Цитата:

Сообщение от ksa
Есть прогеры, которые специально используют особенности ЯП дабы специально и максимально запутать код программы.
В том случае просто сэкономили на одной переменной и видал какой резонанс.

Мое мнение - не стоит так поступать.

Вообщем я вас услышал!Решение задачи должно быть как можно более понятней.Решил по другому:
function nod(a, b) {
  while (a != 0 && b != 0) {
        if (a > b) {
            a = a % b;
        } else {
            b = b % a;
        }
    }
    return a + b;  
}
alert(nod(30, 18));

Спасибо всем за ответы и советы!:)

laimas 17.09.2018 14:37

Цитата:

Сообщение от AlexanderFilatov
Например здесь он сначала вычисляет значение в скобках, а потом использует новое значение переменной "a" при операции делении

Сделайте вывод в консоль текста выражения с подстановкой переменных, и вы поймете, что далеко не так будет.

Выше же написано, что в функции новое значение переменной а будет использоваться на следующей итерации. При этом в самом выражении до вычисления вместо переменных будут взяты их текущие (!) значения. Еще выше было же:

x * (y + 18),

вспоминайте школу.

В вашем же выражении новое значение а получаемой ею в скобках нигде не используется, это действие у вас просто бессмыслица.

Dilettante_Pro 17.09.2018 14:48

laimas,
тогда почему
var b = 10, a = 5;
a = (a = b) / a;
alert(a); // 1

и
var b = 10, a = 5;
a = (a = b) / b;
alert(a); // 1

a
var b = 10, a = 5;
a = a  / b;
alert(a); // 0.5

laimas 17.09.2018 15:00

Потому, что у оператора присваивания ассоциация правая, и у деления левая.

laimas 17.09.2018 15:12

Dilettante_Pro, верно замечания, только сейчас врубился к чему, я то все делаю упор о бессмысленности данного действия в этом случае, в отличии от функции. :)

laimas 17.09.2018 16:02

AlexanderFilatov, "вычислить/запомнить/использовать вычисленное" в вашем контексте бывает полезно в тернарном операторе (можно и N вычислений делать, выражений перечисляемых через запятую). Например нужно проверить вычисляемое значение после чего использовать это значение, либо значение по умолчанию. Чтобы не производить вычисление дважды:

вычислить и сравнить ? вычислить и использовать: значение по умолчанию

можно поступить так:

(a = выражение) == b ? a : x

AlexanderFilatov 18.09.2018 06:54

Цитата:

Сообщение от laimas
Сделайте вывод в консоль текста выражения с подстановкой переменных, и вы поймете, что далеко не так будет.

Выше же написано, что в функции новое значение переменной а будет использоваться на следующей итерации. При этом в самом выражении до вычисления вместо переменных будут взяты их текущие (!) значения. Еще выше было же:

x * (y + 18),

вспоминайте школу.

В вашем же выражении новое значение а получаемой ею в скобках нигде не используется, это действие у вас просто бессмыслица.

laimas, этот пример был не из функции.Насчет тернарного оператора спасибо, буду использовать.Школу достаточно хорошо помню:thanks:


Часовой пояс GMT +3, время: 17:47.