Короткие записи и порядок вычислений
Запись score = score + 5 («возьми счёт, прибавь 5, положи обратно») встречается так часто, что язык завёл сокращение: score += 5. Точно так же сокращаются и другие арифметические присваивания: -=, *=, /=, %= и **=.
let score = 10;// то же, что score = score + 5score += 5;console.log(score); // 15score -= 3; // score = score - 3score *= 2; // score = score * 2score /= 4; // score = score / 4score %= 5; // score = score % 5console.log(score); // 1И одна оговорка, чтобы += не закрепился как чисто числовой: он работает и со строками – дописывает текст справа:
let text = 'Привет';text += '!';console.log(text);А для самого частого случая – изменить ровно на единицу – есть записи ещё короче: score++ увеличивает на 1, score-- уменьшает. Их зовут инкрементом и декрементом. Инкремент считает накопленное (очки, верные ответы – от нуля вверх), декремент – оставшееся (попытки, секунды – от запаса к нулю).
let correct = 0;// верный ответ – счёт растётcorrect++;correct++;console.log(correct); // 2let attempts = 3;attempts--; // попытка потраченаconsole.log(attempts); // 2Префикс и постфикс
И у инкремента, и у декремента есть две формы записи. Знаки после переменной (score++) называются постфиксной формой, знаки до неё (++score) – префиксной. Обе делают одно и то же со счётом: меняют его на единицу.
Разница – в том, какое значение отдаёт сама запись. score++ – не только команда, но и выражение: у него есть значение, как у 2 + 3, – его можно напечатать или положить в переменную. Постфиксная форма сначала отдаёт старое значение и только потом меняет переменную. Префиксная – наоборот: сначала меняет, потом отдаёт новое.
Пока значение записи никто не читает, формы неотличимы: строка score++; и строка ++score; делают одно и то же. Разница проявляется, только когда вы одновременно меняете и читаете – кладёте запись в переменную или печатаете. Пройдите по шагам:
let x = 5;// 5 – постфикс: сначала отдал старое, потом увеличилconsole.log(x++);// 6 – переменная уже измененаconsole.log(x);let y = 5;// 6 – префикс: сначала увеличил, потом отдал новоеconsole.log(++y);console.log(y); // 6Новые операторы встают на знакомую лестницу: счётчики и унарные – выше арифметики, присваивания – ниже всего. Это не полная таблица JavaScript – только лестница операторов, которые вы уже изучили:
Проверим лестницу на двух ступенях: унарный минус срабатывает раньше умножения, а присваивание дожидается всю правую часть:
// -6 – унарный минус сработал раньше умноженияconsole.log(-2 * 3);let total;// присваивание последним: сначала вся правая часть, 2 + 12 → 14total = 2 + 3 * 4;console.log(total); // 14Теперь соберём операторы урока в одну программу и пройдём её по шагам – видно, как лестница решает порядок на каждой строке:
score – 10.Программа подлиннее – скидка, умножение и остаток в одной цепочке вычислений:
let price = 100;const qty = 3;price -= 10; // скидка: в price уже 90// умножение раньше сложения: 270 + 50let total = price * qty + 50;total %= 100; // 320 % 100 → 20console.log(total);Скобки – верхняя ступень: всё внутри них считается первым, поэтому ими можно переписать любой порядок лестницы.
// 14 – умножение раньше сложенияconsole.log(2 + 3 * 4);// 20 – скобки переиграли порядокconsole.log((2 + 3) * 4);Средние ступени: степень сильнее умножения, а умножение, деление и остаток стоят на одной ступени – и все они сильнее сложения с вычитанием.
// 18 – сначала 3 ** 2, потом умножение (не 36)console.log(2 * 3 ** 2);// 8 – остаток на ступени умножения: 10 - 2console.log(10 - 8 % 3);// 4 – деление раньше сложенияconsole.log(2 + 6 / 3);Нижняя ступень – все присваивания разом, включая сокращённые. Правая часть всегда считается целиком до записи: price *= 2 + 3 умножает на 5, а не «умножает на 2 и прибавляет 3».
let price = 4;// сначала правая часть: 2 + 3 → 5, потом price * 5price *= 2 + 3;console.log(price); // 20 – не 11Направление вычислений: слева направо и справа налево
Приоритет решает, какой оператор сработает раньше. Но когда подряд стоят операторы одной ступени, нужен второй закон – направление. Большинство знакомых операторов группируются слева направо: 10 - 4 - 3 – это (10 - 4) - 3 → 3, а не 10 - (4 - 3) → 9.
// 3 – слева направо: (10 - 4) - 3, не 10 - (4 - 3)console.log(10 - 4 - 3);// 1 – (20 / 4) / 5, а не 20 / (4 / 5)console.log(20 / 4 / 5);// 6 – минус и плюс на одной ступени: (7 - 3) + 2console.log(7 - 3 + 2);// '33' – сначала 1 + 2, потом склейка с '3'console.log(1 + 2 + '3');// '123' – склейка началась с первой же парыconsole.log('1' + 2 + 3);Из уже изученного справа налево группируются три конструкции: возведение в степень, тернарный оператор и присваивания. У присваивания это видно в цепочке a = b = 5: сначала b = 5 – у этой записи, как и у счётчиков, есть собственное значение (только что записанная пятёрка), – и оно присваивается a: обе переменные получают 5. У степени – в двойной записи 2 ** 3 ** 2: сначала 3 ** 2 → 9, затем 2 ** 9 → 512, а не 8 ** 2 → 64.
Тернарник тоже связывается справа налево – ещё одна причина, по которой вложенные тернарники читаются с трудом.
let a;let b;// сначала b = 5, его результат – в aa = b = 5;console.log(a, b); // 5 5// 512 – сначала 3 ** 2 → 9, потом 2 ** 9console.log(2 ** 3 ** 2);// теперь вы знаете
- Короткие записи
+=-=*=/=%=**=и счётчики++/--меняют переменную на месте - Постфикс
x++отдаёт старое значение, префикс++x– новое; в одиночной строке формы неотличимы - Присваивания – нижняя ступень лестницы приоритетов: правая часть считается целиком
- Внутри ступени операторы группируются слева направо; степень, тернарник и присваивания – справа налево
В score лежит 7. Что окажется в переменной после score %= 4?
Что окажется в переменных после let x = 5; const y = x++;?
Чему равно 2 ** 3 ** 2?
В score лежит 4. Что будет после score *= 2 + 3?