Операторы и математика
Здесь будет встроен видео-разбор темы (5–7 минут, YouTube / RuTube / VK Видео) — тем, кто лучше воспринимает на слух, текст ниже не обязателен.
Оператор — это действие над данными: сложить, сравнить, выбрать одно из двух. Большая часть знакома со школы, но у JavaScript есть и собственные фокусы — вроде плюса, который ничего не складывает, и строки "2", которая больше "12".
Два слова из жаргона, которые пригодятся: операнд — то, к чему оператор применяется (в записи 5 * 2 операнды — пятёрка и двойка), а сам оператор бывает бинарным (два операнда) или унарным (один). Сложение, вычитание, умножение и деление работают ровно так, как вы ждёте:
Дальше два оператора, которых в школьной тетради не было. Знак % — это не проценты, а остаток от деления: 10 % 3 означает «сколько останется, если из десяти забрать все целые тройки». Самое частое применение — проверка чётности: у чётного числа остаток от деления на 2 всегда ноль. А ** возводит в степень.
Оператор ** принимает и дробные степени, а из математики известно: степень 1/2 — квадратный корень, 1/3 — кубический. Так что корень можно взять без всяких специальных функций.
Оговорка: дробная степень считается приближённо, и везение примера выше не правило — 64 ** (1 / 3) вернёт 3.9999999999999996 вместо тройки. Поэтому в расчётах корень берут не степенью, а Math.sqrt и Math.cbrt: они сделаны ровно под это и не промахиваются.
У плюса есть вторая жизнь. Бинарный a + b складывает, а унарный — стоящий перед одним операндом — ничего не прибавляет, зато превращает операнд в число. С числом он не делает ничего, а вот строку или булево значение конвертирует — ровно как функция Number(), только на семь символов короче. Одно исключение: bigint унарный плюс не берёт вовсе — на +10n он бросает TypeError, а Number(10n) спокойно отдаёт 10.
Зачем это нужно? Данные из HTML-форм и сетевых запросов почти всегда приходят строками. Если сложить две такие «строки-числа» обычным плюсом, они склеятся, а не сложатся — плюс при виде строки работает как клей. Унарный плюс чинит это в одно движение:
Когда в выражении несколько операторов, порядок определяет приоритет — у каждого оператора есть свой номер в длинной официальной таблице. Запоминать её не нужно, достаточно интуиции из школы: унарные операторы сильнее бинарных (поэтому в примере выше +apples сработал раньше сложения), умножение и деление сильнее сложения и вычитания. А всё, что хочется сделать первым, просто берётся в скобки — у них приоритет выше всех.
Практическое правило: если при чтении выражения приходится вспоминать таблицу приоритетов — поставьте скобки. Интерпретатору всё равно, а человеку, который будет читать код после вас, станет заметно легче.
Увеличение и уменьшение на единицу — настолько частая операция, что для неё выделили отдельные операторы: ++ (инкремент) и -- (декремент). Применять их можно только к переменным — запись 5++ вызовет ошибку, ведь пятёрку нельзя «изменить».
Тонкость в том, что ++ можно поставить и до, и после переменной, и переменная в обоих случаях увеличится одинаково. Разница видна, только когда результат сразу используется: префиксная форма ++a возвращает уже новое значение, а постфиксная a++ — ещё старое.
++i — сначала прибавь, потом отдай. i++ — сначала отдай.
Операторы сравнения — >, <, >=, <= — всегда возвращают булево значение: true или false. Результат можно сохранить в переменную или использовать сразу.
Сравнивать можно и строки — JavaScript идёт по ним посимвольно, как при расстановке слов в словаре: сравнил первые символы, при равенстве перешёл ко вторым, и так далее. Для слов это работает ожидаемо, а вот для «строк-чисел» превращается в ловушку: сравниваются символы, а не величины.
В примере с "2" > "12" JavaScript сравнил первые символы — "2" и "1" — и на этом остановился: двойка в таблице символов дальше единицы, значит true. Если операнды означают числа, приведите их к числам унарным плюсом до сравнения — и ловушка исчезнет. Остальные странности сравнений — почему операнды разных типов становятся числами и почему null равен только undefined — разбирает статья «Сравнения и их ловушки».
Единственный оператор с тремя операндами — потому и тернарный. Записывается как условие ? значение1 : значение2 и читается как вопрос: условие истинно? Тогда возьми первое значение, иначе — второе. Это самый короткий способ выбрать одно из двух.
Тернарный оператор хорош именно для выбора значения. Когда по условию нужно выполнить разные действия или ветвление разрастается, читаемее конструкция if/else — её и сам тернарный оператор в роли ветвления разбирает статья «Условия: if, else и тернарный оператор».
В JavaScript есть и оператор , — он вычисляет несколько выражений подряд, а возвращает результат только последнего. Встречается в минифицированном коде и старых хитрых циклах, но в своём коде он не нужен: то же самое яснее записывается отдельными строками.
- Арифметика почти школьная, но с двумя новичками:
%— остаток от деления (удобен для проверки чётности),**— возведение в степень. - Унарный плюс
+x— самый короткий способ превратить строку в число;Number(x)делает то же и вдобавок умеетbigint, которого плюс не берёт. - Не помните приоритет операторов — ставьте скобки: они главнее любой таблицы и делают код читаемее.
++iвозвращает уже увеличенное значение,i++— ещё старое; сама переменная растёт в обоих случаях.- Строки сравниваются посимвольно, поэтому
"2" > "12"—true; а выбор одного из двух значений удобно записывать тернарным операторомусловие ? а : б.
1/3Что выведет console.log(2 + 2 * 2)?
2/3Есть код: let i = 5; console.log(i++); Что попадёт в консоль?
3/3Что вернёт выражение "2" > "12"?
Та же сумма, но короче
Тот же случай, что в задаче «Почини сумму» из статьи «Преобразование типов: где JavaScript вас удивит»: данные пришли из формы, поэтому оба значения — строки, и код печатает "105". Только теперь под рукой унарный плюс. Исправьте последнюю строку так, чтобы вывелось число 15, не трогая объявления переменных.
Унарный плюс превращает каждую строку в число ещё до сложения: console.log(+a + +b); // 15. Унарные операторы срабатывают раньше бинарного плюса, поэтому дополнительные скобки не нужны.
Предскажи инкременты
Не запуская код, определите, что напечатает каждый console.log. Потом запустите и сверьтесь.
++a увеличивает a до 2 и возвращает 2 — это b. Затем a++ возвращает текущие 2 (это c) и после увеличивает a до 3. Вывод: 3, 2, 2.