Операторы — это то, как выражения выполняют работу
Практически любая нетривиальная строка JavaScript состоит из операторов — символов, которые берут одно или два значения и возвращают новое. + складывает, === сравнивает, && объединяет булевы значения, ? : выбирает одно из двух. Большинство операторов в js знакомы по другим языкам, но у некоторых есть свои особенности, о которых стоит знать заранее.
Пройдёмся по ним по категориям, а в конце разберём те, что нужны реже, но без которых в нужный момент не обойтись.
Арифметические операторы
С базовыми всё предсказуемо:
Стоит обратить внимание на несколько моментов:
/— это всегда деление с плавающей точкой.7 / 2даст3.5, а не3. Если нужен именно целочисленный результат, используйтеMath.floor(7 / 2)илиMath.trunc(7 / 2).%возвращает остаток, а не математический модуль. Знак результата совпадает со знаком левого операнда:-7 % 3— это-1, а не2.+— оператор с двойным смыслом. Если хотя бы один из операндов — строка, происходит не сложение, а конкатенация:"3" + 1даёт"31". Об этом чуть ниже подробнее.
Инкремент и декремент
Разница между count++ и ++count проявляется только тогда, когда значение выражения используется прямо в той же строке. Если это самостоятельный оператор, они делают одно и то же. Большинство стайл-гайдов вообще рекомендуют писать count += 1 — так понятнее.
У оператора + раздвоение личности
Вот на этом хоть раз спотыкался каждый:
Если хотя бы один из операндов — строка, + превращается в конкатенацию и приводит вторую сторону к строке. Все остальные арифметические операторы работают наоборот: строки приводятся к числам:
Главное правило: когда собираете строки — используйте шаблонные литералы (`price: ${5}`). А когда считаете числа — убедитесь, что на вход действительно приходят числа: Number(x) или parseInt(x, 10) приводят типы явно.
Операторы сравнения в JavaScript
Операторы сравнения возвращают булево значение. Есть два варианта: строгое и нестрогое сравнение.
=== и !== — это строгое сравнение: и значение, и тип должны совпадать. А вот == и != сначала приводят типы, и из-за этого случаются сюрпризы вроде null == undefined, который возвращает true, или [] == false, тоже true. По умолчанию используйте === и !==. Единственное распространённое исключение — конструкция x == null: удобный способ проверить, равно ли x либо null, либо undefined.
Операторы сравнения работают с числами так, как и ожидаешь, а со строками — по алфавиту:
Сравнение строк идёт по кодам символов, поэтому регистр имеет значение. Если нужна «человеческая» сортировка — используйте String.prototype.localeCompare.
Логические операторы js
&& (И), || (ИЛИ) и ! (НЕ) умеют комбинировать булевы значения — но на практике они работают интереснее, чем можно было бы ожидать от чистой булевой алгебры.
Нюанс вот в чём: && и || возвращают не true или false, а один из своих операндов. && вернёт первое falsy-значение, либо последнее, если все значения truthy. || — первое truthy-значение, либо последнее, если все falsy.
Именно поэтому вы часто встретите такие конструкции, как const displayName = user.name || "Guest" — берём первое непустое значение. Коротко и ёмко, но есть нюанс: || считает 0, "" и false поводом взять запасной вариант. Если для вас это валидные значения, используйте ?? (о нём ниже).
Оба оператора работают по принципу короткого замыкания: если левая часть уже определяет результат, правая просто не выполняется.
Оператор нулевого слияния ??
Оператор ?? в javascript работает похоже на ||, но срабатывает только на null или undefined — значения 0, "" и false он пропускает как вполне валидные.
Используйте ??, если валидным значением может быть что-то ложное — ноль, пустая строка, явный false. А || берите, когда любое ложное значение должно означать «ничего нет». В современном коде ?? — более безопасный выбор по умолчанию для необязательных значений с ненулевым дефолтом.
Оператор присваивания в JavaScript
= просто присваивает значение. Составные формы объединяют присваивание с каким-нибудь другим оператором:
Есть ещё логические операторы присваивания — ||=, &&= и ??=, которые записывают новое значение только при выполнении определённого условия:
Такие конструкции удобны, когда нужно подставить значение по умолчанию без громоздких if.
Тернарный оператор в JavaScript
Запись условие ? a : b — это выражение-аналог if/else. Если условие истинно, возвращается a, иначе — b:
Тернарный оператор хорош для коротких выборок значения. Но как только вы начинаете его вкладывать — превращается в головоломку: если у вас получается a ? b : c ? d : e, лучше взять if/else или объект-словарь.
Оператор typeof и instanceof в JavaScript
Оператор typeof возвращает строку с типом своего операнда:
Пара граблей, которые стоит запомнить раз и навсегда: typeof null возвращает "object" (баг из 1995 года, который уже никогда не починят), а массивы тоже определяются как "object". Поэтому для массивов используйте Array.isArray(x), а для null — обычное x === null.
Оператор instanceof проверяет, был ли объект создан на основе конкретного конструктора:
Spread и rest — один и тот же ...
Синтаксис ... встречается в двух ситуациях. В роли spread он «разворачивает» итерируемый объект на отдельные элементы:
В роли rest он, наоборот, собирает несколько значений в один массив — обычно в параметрах функции или при деструктуризации:
Синтаксис один — задачи противоположные. Spread распаковывает, rest собирает. Кто из них кто — решает контекст: в вызове или литерале это spread, в списке параметров или шаблоне деструктуризации — rest.
Приоритет операторов в JavaScript (если сомневаетесь — ставьте скобки)
У операторов есть приоритет, который определяет, какой из них выполнится первым, когда вы их смешиваете. Умножение важнее сложения, сравнение важнее логических операторов, и так далее:
Полную таблицу никто наизусть не держит — да это и не нужно. Простая привычка закрывает 99% случаев: если в выражении смешаны разные операторы и вы не уверены в порядке вычислений — ставьте скобки. Код становится читаемее и не зависит от памяти того, кто его читает.
Побитовые операторы (скорее всего, вам не они нужны)
Для полноты картины: &, |, ^, ~, <<, >> и >>> работают с двоичным представлением целых чисел. Встретить их можно в коде для графики, в низкоуровневых протоколах и изредка — в API с флагами-битмасками.
Один распространённый, но сомнительный трюк: n | 0 усекает число до 32-битного целого, и раньше это использовали как более быструю замену Math.trunc. Не надо так — Math.trunc понятнее и работает с числами за пределами 32-битного диапазона.
Дальше: if/else
Операторы возвращают значения, а if/else на основе этих значений выбирает, какую ветку кода выполнить. По сути, большую часть времени вы будете скармливать результаты операторов сравнения и логических операторов именно в условные конструкции — об этом и пойдёт речь на следующей странице.
Часто задаваемые вопросы
Какие основные операторы есть в JavaScript?
В JavaScript есть арифметические (+, -, *, /, %, **), сравнения (===, !==, <, >), логические (&&, ||, !), присваивания (=, +=, -=), а также несколько специальных: тернарный ? :, typeof и оператор нулевого слияния ??. Из них и собираются все выражения и условия в коде.
Чем отличается == от === в JavaScript?
=== сравнивает и значение, и тип — строго. А == сначала приводит типы, поэтому 0 == "0" даёт true, хотя 0 === "0" — это false. По умолчанию всегда используйте ===: правила приведения у == достаточно хитрые, чтобы породить баг, который никто не заметит на ревью.
Что делает тернарный оператор в JavaScript?
condition ? a : b — это однострочный if/else, который возвращает значение. Если condition истинно, выражение равно a, иначе — b. Удобно для коротких условий вроде const label = count === 1 ? 'item' : 'items', но вложенные тернарники быстро превращаются в нечитаемую кашу.
Когда использовать ?? вместо ||?
|| срабатывает на любое falsy-значение — включая 0, "" и false. А ?? реагирует только на null и undefined. Если в count ?? 10 вам важно сохранить честный 0 — берите ??. Если же вы действительно хотите, чтобы любое falsy-значение включало fallback, оставляйте ||.