JS / Основы

JavaScript. Основы. Переменные. Операторы

Разбираем переменные, типы данных и операторы JavaScript на понятных примерах: от let и const до калькулятора заказа, отладки и заданий с ответами.

Опубликовано 08.09.2026 47 минут чтения
Содержание статьи

Большая практическая статья для тех, кто начинает программировать. С понятными аналогиями, экспериментами, мини-проектом и заданиями с ответами.

Представьте, что вы открываете маленькую кофейню. Нужно помнить стоимость напитков, считать сдачу, учитывать скидки и решать, кому полагается бесплатная доставка. Пока посетителей мало, можно делать всё в голове. Но уже через час хочется поручить расчёты кому-нибудь другому.

Компьютер готов помочь. Есть только одна особенность: он не понимает фразу «посчитай как обычно». Ему нужны точные данные и точные инструкции.

Переменные позволяют дать данным имена. Операторы объясняют, что с этими данными делать. Вместе они превращают набор чисел и строк в работающую программу.

В этой статье мы разберёмся, почему "5" + 2 даёт "52", зачем нужны сразу let и const, чем присваивание отличается от сравнения и как из нескольких простых выражений получается калькулятор заказа.

Как читать статью

Не пытайтесь запомнить все операторы за один вечер. Прочитайте раздел, выполните пример, измените одно значение и попробуйте заранее предсказать результат. Именно такое маленькое «а что будет, если…» превращает чтение в навык.

Каждый блок JavaScript в статье — отдельный пример. Запускайте его отдельно: в разных блоках могут повторяться имена переменных. Строки с намеренными ошибками обычно закомментированы. Если захотите увидеть ошибку самостоятельно, уберите // только у нужной строки.

1. Что такое JavaScript и где выполнять код

JavaScript — язык программирования. В браузере он может реагировать на нажатия кнопок, проверять поля формы, пересчитывать стоимость заказа и обновлять страницу без полной перезагрузки.

Для первого знакомства удобно представить сайт как кафе:

  • HTML — помещение и предметы: стойка, столики, меню, кнопка вызова официанта.
  • CSS — оформление: цвета, шрифты, расстояния и расположение элементов.
  • JavaScript — действия: нажали кнопку, изменили заказ, получили новую сумму.

Это учебная аналогия, а не строгое разделение возможностей: например, простые анимации доступны и в CSS. Но она помогает понять главную роль JavaScript — описывать поведение.

JavaScript работает не только в браузере. Например, среда Node.js позволяет выполнять его вне браузера. Однако для этой статьи достаточно браузерной консоли: устанавливать дополнительные программы не обязательно.

Первый запуск

Откройте инструменты разработчика браузера и найдите вкладку Console / Консоль. В настольных браузерах для этого часто используют F12 или пункт «Инструменты разработчика» в меню.

Введите вручную:

JavaScript
console.log("Привет! Я начинаю изучать JavaScript.");​

Вы увидите сообщение:

Код
Привет! Я начинаю изучать JavaScript.​

console.log(...) выводит переданные значения в консоль. Пока воспринимайте его как диагностическое окошко: мы просим программу показать, что получилось.

После сообщения консоль может дополнительно показать undefined. Это результат самого вызова console.log, а не ошибка и не часть вашего текста.

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

Если удобнее запускать код из файла

Создайте файл index.html и вставьте в него:

HTML
<!doctype html><html lang="ru">  <head>    <meta charset="UTF-8">    <title>Изучаю JavaScript</title>  </head>  <body>    <h1>Мои первые эксперименты</h1>​    <script>      "use strict";​      const message = "JavaScript работает!";      console.log(message);    </script>  </body></html>​

Откройте файл в браузере и посмотрите в консоль. При изменении кода сохраните файл и обновите страницу.

"use strict" включает строгий режим для этого скрипта. Он, в частности, помогает обнаруживать случайное присваивание необъявленной переменной. В JavaScript-модулях строгий режим действует автоматически, но модули — тема следующего этапа обучения.

2. Как читать первые строки программы

Посмотрим на небольшую программу:

JavaScript
const coffeePrice = 180;const coffeeCount = 2;const totalPrice = coffeePrice * coffeeCount;​console.log(totalPrice); // 360​

Читается она почти как инструкция для сотрудника кофейни:

  1. Цена кофе — 180.
  2. Покупатель заказал два кофе.
  3. Общая стоимость — цена, умноженная на количество.
  4. Покажи общую стоимость.

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

Комментарии: заметки для человека

Текст после // до конца строки — комментарий. Он не выполняется как код.

JavaScript
// Один стакан стоит 180 рублей.const price = 180;​/*  Здесь может быть пояснение  из нескольких строк.*/console.log(price);​

Хороший комментарий объясняет причину решения, а не просто повторяет код:

JavaScript
// Скидка действует только на товары, доставка оплачивается отдельно.const discountedGoodsPrice = 2000 * 0.9;​console.log(discountedGoodsPrice); // 1800​

Точки с запятой и пробелы

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

Для начала проще придерживаться последовательного стиля: одна инструкция на строку, понятные отступы, точки с запятой там, где они стоят в примерах.

Пробелы вокруг операторов обычно не меняют результат, зато сильно помогают чтению:

JavaScript
const total = 180 * 2 + 50;​console.log(total); // 410​

Код читают чаще, чем пишут. В том числе вы сами, когда вернётесь к нему через неделю.

3. Переменная: имя для значения

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

Для первого знакомства представим переменную как коробку с наклейкой:

  • на наклейке написано userName;
  • внутри лежит значение "Анна";
  • чтобы получить содержимое, мы обращаемся по имени userName.
JavaScript
let userName = "Анна";​console.log(userName); // Анна​

Разберём строку объявления:

Часть Значение
let Объявляем переменную, которой позже можно присвоить другое значение
userName Имя переменной
= В этой записи задаём начальное значение
"Анна" Строковое значение
; Завершаем инструкцию

Объявление, инициализация и присваивание

Эти слова описывают разные действия.

Объявить переменную — создать в программе имя. Инициализировать — задать начальное значение. Присвоить — записать значение в уже объявленную переменную.

JavaScript
let deliveryPrice;console.log(deliveryPrice); // undefined​deliveryPrice = 300;console.log(deliveryPrice); // 300​deliveryPrice = 0;console.log(deliveryPrice); // 0​

После выполнения let deliveryPrice; переменная уже существует и имеет значение undefined. Затем мы дважды меняем её значение.

Чаще объявление и начальное значение записывают вместе:

JavaScript
let deliveryPrice = 300;​console.log(deliveryPrice); // 300​

Присваивание — не математическое равенство

В математике запись x = x + 1 выглядит странно. В программировании она совершенно нормальна:

JavaScript
let visitorsCount = 10;​visitorsCount = visitorsCount + 1;​console.log(visitorsCount); // 11​

Программа сначала вычисляет правую часть: берёт прежнее значение 10, прибавляет 1 и получает 11. Затем записывает результат в переменную слева.

Представьте табло посетителей: сотрудник посмотрел на число, прибавил одного человека и заменил показание табло. Здесь нет утверждения, что десять равно одиннадцати. Есть команда обновить данные.

Копирование не создаёт вечную связь

JavaScript
let firstPrice = 500;let secondPrice = firstPrice;​firstPrice = 700;​console.log(firstPrice);  // 700console.log(secondPrice); // 500​

В момент присваивания в secondPrice попало число 500. Это не формула, которая обязана пересчитываться при изменении firstPrice.

Аналогия: вы переписали цену с ценника в блокнот. Если магазин поменяет ценник, запись в блокноте сама не изменится.

С объектами есть важный нюанс: несколько переменных могут указывать на один объект. До этого мы скоро дойдём, и тогда уточним модель коробки.

4. Как выбирать имена переменных

Имя должно подсказывать, что означает значение.

Сравните:

JavaScript
const a = 1500;const b = 3;const c = a * b;​console.log(c); // 4500​

И тот же расчёт:

JavaScript
const productPrice = 1500;const productCount = 3;const orderTotal = productPrice * productCount;​console.log(orderTotal); // 4500​

Во втором примере смысл понятен без расшифровки. Имена — это встроенная документация программы.

Основные правила

Для привычных латинских имён действуют простые ориентиры:

  • Начинайте имя с буквы, _ или $, но не с цифры.
  • Не используйте пробелы и дефисы внутри имени.
  • Учитывайте регистр: userName и username — разные имена.
  • Не используйте зарезервированные слова вроде class, return или const как обычные имена переменных.
JavaScript
const userName = "Олег";const product2Price = 900;const _internalValue = 10;const $buttonLabel = "Купить";​console.log(userName, product2Price, _internalValue, $buttonLabel);​// const 2product = "Книга"; // Ошибка: имя начинается с цифры.// const user-name = "Олег"; // Ошибка: дефис не является частью имени.​

JavaScript допускает и многие Unicode-буквы, в том числе кириллицу. Но в учебном и командном коде обычно удобнее английские имена: их проще сочетать с названиями встроенных возможностей языка.

Стиль camelCase

Первое слово пишут со строчной буквы, каждое следующее начинают с заглавной:

JavaScript
const userEmail = "student@example.com";const cartTotalPrice = 2500;const isDeliveryAvailable = true;​console.log(userEmail, cartTotalPrice, isDeliveryAvailable);​

Логические значения удобно называть как вопросы: isOpen — «открыто?», hasDiscount — «есть скидка?», canOrder — «можно заказать?».

Для заранее известных констант-настроек нередко используют другой стиль:

JavaScript
const MAX_PRODUCTS_PER_ORDER = 20;const FREE_DELIVERY_THRESHOLD = 5000;​console.log(MAX_PRODUCTS_PER_ORDER, FREE_DELIVERY_THRESHOLD);​

Но объявление через const само по себе не требует заглавных букв. Например, const userName = "Анна" — обычное и хорошее имя.

Ещё полезно указывать единицы измерения: delayMs, distanceKm, priceKopecks. Ошибка «секунды приняли за миллисекунды» выглядит очень буднично, пока программа не начинает ждать в тысячу раз дольше.

5. let, const и var

В обычном прикладном коде вам постоянно будут встречаться три способа объявления переменных: let, const и var. Начнём с первых двух.

let: значение предполагается менять

JavaScript
let score = 0;​score = 10;score = 25;​console.log(score); // 25​

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

В одной области видимости нельзя повторно объявить это же имя через let:

JavaScript
let score = 0;​// let score = 10; // SyntaxError: повторное объявление.​score = 10; // А присвоить новое значение можно.​console.log(score); // 10​

const: нельзя переприсвоить переменную

JavaScript
const shopName = "Кофе и код";​console.log(shopName); // Кофе и код​// shopName = "Другая кофейня"; // TypeError.​

У обычного объявления const сразу должно быть начальное значение:

JavaScript
const deliveryPrice = 250;​console.log(deliveryPrice); // 250​// const anotherPrice; // SyntaxError: нет начального значения.​

Важно: const не означает «значение известно заранее, до запуска программы». Оно может быть вычислено:

JavaScript
const price = 700;const quantity = 4;const total = price * quantity;​console.log(total); // 2800​

Смысл const здесь такой: после создания переменной total мы не собираемся записывать в неё другой результат.

const не замораживает объекты

Объект объединяет связанные данные. Например, у пользователя есть имя и количество бонусов:

JavaScript
const user = {  name: "Анна",  bonusPoints: 100};​user.bonusPoints = 150;​console.log(user.bonusPoints); // 150​// user = { name: "Игорь", bonusPoints: 0 }; // TypeError.​

Мы не заменили объект, на который указывает user. Мы изменили свойство существующего объекта. const запрещает первое, но не запрещает второе.

Здесь модель коробки нуждается в уточнении. Для объекта удобно представить, что в коробке лежит карточка с адресом дома. const запрещает заменить карточку на адрес другого дома. Но переставлять мебель в самом доме по-прежнему можно.

Из этого следует важный эффект:

JavaScript
const firstUser = { name: "Анна" };const secondUser = firstUser;​secondUser.name = "Мария";​console.log(firstUser.name); // Мария​

Обе переменные указывают на один объект. Они не получили два независимых дома: у них две карточки с одним адресом.

С массивами ситуация аналогична. Массив — упорядоченная коллекция значений:

JavaScript
const products = ["Кофе", "Чай"];​products.push("Какао");​console.log(products.length); // 3console.log(products[2]);     // Какао​// products = []; // TypeError.​

push добавляет элемент в существующий массив, length сообщает количество элементов, а [2] обращается к третьему элементу: индексация начинается с нуля.

var: нужно узнавать в чужом коде

var — более старый способ объявления. Он не удалён из языка, но имеет особенности, которые усложняют обучение: например, не ограничивается обычным блоком { ... } и допускает повторные объявления через var.

JavaScript
var message = "Первое сообщение";var message = "Второе сообщение";​console.log(message); // Второе сообщение​

Для нового учебного кода достаточно правила: используйте const по умолчанию, а let — когда действительно потребуется переприсваивание. var важно понимать, чтобы читать старые проекты.

Свойство let const var
Можно переприсвоить Да Нет Да
Можно объявить без начального значения в обычной инструкции Да Нет Да
Ограничивается обычным блоком { ... } Да Да Нет
Повторное объявление тем же ключевым словом в одной области Нет Нет Да
Учебный ориентир Для изменяемой переменной Основной выбор Для понимания старого кода

Формальные правила объявлений и областей видимости можно дополнительно посмотреть в руководстве MDN по грамматике и типам.

6. Область видимости и обращение до объявления

Область видимости — участок программы, в котором доступно имя переменной.

Представьте офис с комнатами. Объявление снаружи комнаты можно увидеть изнутри, если внутреннее имя его не заслоняет. Но записка, оставленная внутри закрытой комнаты, не становится доступной всему офису.

JavaScript
const shopName = "Кофе и код";​{  const localDiscount = 10;​  console.log(shopName);      // Кофе и код  console.log(localDiscount); // 10}​console.log(shopName); // Кофе и код​// console.log(localDiscount); // ReferenceError: имя недоступно здесь.​

В данном примере фигурные скобки создают блок. Это не объект: контекст использования скобок имеет значение.

Одинаковые имена в разных областях

JavaScript
const city = "Казань";​{  const city = "Москва";  console.log(city); // Москва}​console.log(city); // Казань​

Внутреннее объявление затеняет внешнее. Оно не меняет внешнюю переменную, а создаёт отдельную переменную с таким же именем.

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

Почему var ведёт себя иначе

JavaScript
{  var oldStyleValue = 10;  let modernValue = 20;}​console.log(oldStyleValue); // 10​// console.log(modernValue); // ReferenceError.​

Обычный блок не ограничил var. Внутри функции var ограничивается функцией; на верхнем уровне действуют правила скрипта или модуля.

Можно ли прочитать переменную до объявления?

Для let и const — не до выполнения инициализации соответствующего объявления:

JavaScript
// console.log(price); // ReferenceError, если раскомментировать.​let price = 300;​console.log(price); // 300​

Участок от начала области видимости до инициализации называют временной мёртвой зоной, или TDZ. Не пугайтесь названия: практический вывод простой — объявляйте переменную до использования.

С var получится другой результат:

JavaScript
console.log(price); // undefined​var price = 300;​console.log(price); // 300​

Объявление var обрабатывается заранее, но присваивание 300 происходит только при выполнении соответствующей строки. Это связано с механизмом, который называют hoisting, или «поднятием».

Не нужно представлять, будто JavaScript буквально переносит строки файла. Это способ описать поведение объявлений. let и const тоже обрабатываются до выполнения тела области, но до инициализации недоступны.

7. Типы данных: что лежит в переменной

Операция зависит не только от значения, но и от его типа. Пять яблок и табличка с надписью «5» — не одно и то же. Первое можно прибавить к количеству яблок. Второе можно приклеить к другой надписи.

Числа: number

JavaScript
const age = 25;const temperature = -7;const rating = 4.8;​console.log(age, temperature, rating);​

В обычных числовых литералах дробную часть отделяют точкой, не запятой. Целые и дробные значения чаще всего относятся к одному типу — number.

Для удобства чтения больших чисел можно использовать _ внутри записи:

JavaScript
const yearlyVisitors = 1_000_000;​console.log(yearlyVisitors); // 1000000​

_ здесь не является частью значения: это разделитель для человека.

Строки: string

Строка — текст в кавычках:

JavaScript
const firstName = "Анна";const city = 'Казань';const greeting = `Здравствуйте, ${firstName}!`;​console.log(city);     // Казаньconsole.log(greeting); // Здравствуйте, Анна!​

Одинарные и двойные кавычки создают обычные строки. Обратные кавычки создают шаблонный литерал: внутри ${...} можно подставить результат выражения.

JavaScript
const price = 250;const quantity = 3;​console.log(`За ${quantity} товара: ${price * quantity} ₽`);// За 3 товара: 750 ₽​

Не перепутайте обратные кавычки с одинарными. Строка 'Привет, ${firstName}' не выполнит подстановку.

Логические значения: boolean

У этого типа всего два значения: true и false.

JavaScript
const isShopOpen = true;const hasUnpaidOrder = false;​console.log(isShopOpen);    // trueconsole.log(hasUnpaidOrder); // false​

Аналогия — лампочка-индикатор: включена или выключена. Важно не путать логическое значение false со строкой "false". Строка содержит текст, а не ответ «нет».

undefined: значение не задано

JavaScript
let deliveryDate;​console.log(deliveryDate); // undefined​

Переменная объявлена, но мы не задали ей дату. Позже она может получить конкретное значение.

null: намеренно обозначенное отсутствие

JavaScript
const selectedProduct = null;​console.log(selectedProduct); // null​

Так можно показать: «товар пока не выбран». Различие удобно запоминать как анкету: undefined — ответ не получен, null — явно отмечено отсутствие. Это соглашение о смысле; технически программист может присвоить и undefined вручную.

Объекты и массивы

JavaScript
const product = {  title: "Настольная лампа",  price: 2500,  inStock: true};​const colors = ["Белый", "Чёрный", "Серый"];​console.log(product.title); // Настольная лампаconsole.log(colors[0]);     // Белый​

Объект похож на карточку товара с подписанными полями. Массив — на пронумерованный список. Массивы в JavaScript являются объектами.

Ещё два примитивных типа

Полная картина включает bigint и symbol:

JavaScript
const hugeInteger = 9_007_199_254_740_993n;const uniqueKey = Symbol("productId");​console.log(typeof hugeInteger); // bigintconsole.log(typeof uniqueKey);   // symbol​

bigint позволяет работать с целыми числами за пределами диапазона безопасных целых number. Литерал заканчивается буквой n. Это не инструмент для точных десятичных дробей.

symbol создаёт уникальные значения, которые, например, используют как ключи свойств. На первом этапе достаточно знать, что такой тип существует.

Всего примитивных типов семь: string, number, bigint, boolean, undefined, symbol, null. Помимо них есть объектный тип. У массивов нет отдельного типа на этом уровне классификации.

typeof: спросить у значения его тип

JavaScript
console.log(typeof 42);        // numberconsole.log(typeof "42");      // stringconsole.log(typeof true);      // booleanconsole.log(typeof undefined); // undefinedconsole.log(typeof {});        // objectconsole.log(typeof []);        // objectconsole.log(typeof null);      // object​

Результат typeof — строка. А typeof null === "object" — историческая особенность языка: сам null при этом остаётся примитивным значением, а не объектом.

Если нужно проверить именно null, используйте value === null. Для массива есть Array.isArray(value):

JavaScript
const products = ["Книга", "Лампа"];​console.log(Array.isArray(products)); // true​

Динамическая типизация

В JavaScript тип связан со значением. Переменной, объявленной через let, можно присвоить значение другого типа:

JavaScript
let answer = 42;console.log(typeof answer); // number​answer = "Сорок два";console.log(typeof answer); // string​

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

8. Преобразование типов

Иногда данные приходят не в том виде, который нужен для вычислений. Например, свойство .value обычного HTML-поля ввода содержит строку — даже если человек ввёл цифры.

Представьте записку с текстом «250». Прежде чем использовать её в расчёте, нужно прочитать текст как число.

Явное преобразование

JavaScript
const priceFromInput = "250";const quantityFromInput = "3";​const price = Number(priceFromInput);const quantity = Number(quantityFromInput);​console.log(price * quantity); // 750console.log(typeof price);     // number​

Три полезных инструмента:

Запись Действие Пример результата
Number(value) Преобразует в число Number("25") → 25
String(value) Преобразует в строку String(25) → "25"
Boolean(value) Преобразует в логическое значение Boolean(0) → false

При этом преобразование не заменяет проверку данных:

JavaScript
console.log(Number("120"));    // 120console.log(Number("12.5"));   // 12.5console.log(Number("12,5"));   // NaNconsole.log(Number("120 ₽"));  // NaNconsole.log(Number(""));       // 0console.log(Number("   "));    // 0console.log(Number(null));     // 0console.log(Number(undefined)); // NaN​

Number("") возвращает ноль. Но пустое поле и введённый пользователем ноль часто означают разные вещи. Поэтому в форме нужно отдельно проверять, заполнено ли поле.

NaN: не удалось получить нормальный числовой результат

NaN расшифровывается как Not a Number. Это специальное значение типа number, а не отдельный тип.

JavaScript
const result = Number("кофе");​console.log(result);               // NaNconsole.log(typeof result);        // numberconsole.log(Number.isNaN(result)); // trueconsole.log(result === NaN);       // false​

Последняя строка — важная ловушка: NaN не равен самому себе при сравнении через ===. Проверяйте его с помощью Number.isNaN.

Если нужно обычное конечное число, полезнее проверка Number.isFinite:

JavaScript
console.log(Number.isFinite(120));      // trueconsole.log(Number.isFinite(Infinity)); // falseconsole.log(Number.isFinite(NaN));      // falseconsole.log(Number.isFinite("120"));    // false​

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

Number и parseInt — не одно и то же

JavaScript
console.log(Number("24px"));        // NaNconsole.log(parseInt("24px", 10));  // 24console.log(parseInt("24.9", 10));  // 24console.log(parseFloat("24.9px"));  // 24.9​

Number пытается преобразовать всю строку. parseInt и parseFloat могут прочитать начальную числовую часть и остановиться на неподходящем символе.

Число 10 в parseInt(..., 10) указывает десятичную систему счисления. Не используйте parseInt как универсальную проверку поля: запись "24яблока" может случайно пройти такую «проверку».

Неявное преобразование и загадка плюса

JavaScript
console.log(5 + 2);     // 7console.log("5" + 2);   // 52 (строка)console.log("5" - 2);   // 3console.log("5" * 2);   // 10console.log("10" / 2);  // 5​

У бинарного + две знакомые нам роли: сложение чисел и соединение строк. Если один из операндов после преобразования к примитивному значению является строкой, происходит строковое соединение.

Поэтому "5" + 2 превращается в "5" + "2" и даёт "52". А -, * и / не склеивают текст: для показанных строк они выполняют числовое преобразование.

Здесь легко получить цепную реакцию:

JavaScript
console.log(1 + 2 + "3"); // 33 (строка)console.log("1" + 2 + 3); // 123 (строка)​

В первом случае сначала складываются числа 1 + 2. Во втором склеивание начинается сразу и продолжается дальше.

Практическое правило: на входе в расчёт явно приводите данные к нужному типу. Чем меньше у программы поводов угадывать, тем проще вам понимать результат.

9. Выражения, операторы и операнды

Выражение — фрагмент кода, вычисление которого даёт значение.

JavaScript
console.log(2 + 3);          // 5console.log(10 > 7);         // trueconsole.log("Кофе" + "!");  // Кофе!​

В 2 + 3 знак + — оператор, а 2 и 3 — операнды, то есть то, над чем выполняется действие.

По количеству операндов операторы бывают:

  • унарными — один операнд: !isOpen, -price, typeof value;
  • бинарными — два: price * quantity, age >= 18;
  • тернарными — три: condition ? firstValue : secondValue.

Не всякая конструкция языка является оператором. Например, if — условная инструкция, а const используется в объявлении. Различие станет полезным, когда мы будем выбирать между if и тернарным оператором.

10. Арифметические операторы

Большинство арифметических знаков знакомы со школы:

Оператор Действие Пример Результат
+ Сложение 8 + 3 11
- Вычитание 8 - 3 5
* Умножение 8 * 3 24
/ Деление 8 / 2 4
% Остаток от деления 8 % 3 2
** Возведение в степень 2 ** 3 8

Считаем заказ

JavaScript
const coffeePrice = 180;const coffeeCount = 2;const dessertPrice = 240;​const orderPrice = coffeePrice * coffeeCount + dessertPrice;​console.log(orderPrice); // 600​

Деление не обязательно даёт целое число

JavaScript
console.log(7 / 2); // 3.5​

Если нужно узнать число полных коробок по шесть предметов, это отдельное действие:

JavaScript
const itemsCount = 20;const boxCapacity = 6;​const fullBoxes = Math.floor(itemsCount / boxCapacity);const remainingItems = itemsCount % boxCapacity;​console.log(fullBoxes);      // 3console.log(remainingItems); // 2​

Math.floor округляет вниз. Для положительного количества предметов это даёт число полностью заполненных коробок.

% — не вычисление процентов

17 % 5 даёт 2: из семнадцати конфет можно собрать три полные группы по пять, останутся две конфеты.

Остаток удобно использовать для проверки чётности:

JavaScript
const seatsCount = 18;const canSplitIntoPairs = seatsCount % 2 === 0;​console.log(canSplitIntoPairs); // true​

А процентную скидку считают через деление на сто:

JavaScript
const price = 2000;const discountPercent = 15;​const discountAmount = price * discountPercent / 100;const finalPrice = price - discountAmount;​console.log(discountAmount); // 300console.log(finalPrice);     // 1700​

Для отрицательных значений у % есть особенность: это именно остаток, а не всегда положительный математический модуль. Например, -7 % 3 даёт -1.

Степень и смена знака

JavaScript
console.log(3 ** 2);    // 9console.log(2 ** 5);    // 32console.log(-(3 ** 2)); // -9console.log((-3) ** 2); // 9​

У скобок здесь не декоративная роль. Кроме того, запись -3 ** 2 без нужных скобок является синтаксической ошибкой JavaScript.

Унарный минус меняет знак числа, а унарный плюс может преобразовать значение в число:

JavaScript
const temperature = 7;​console.log(-temperature); // -7console.log(+"250");       // 250​

Для новичка Number("250") обычно понятнее, чем +"250". Унарный плюс стоит узнавать в чужом коде; также он не поддерживает преобразование bigint.

Деление на ноль

Для чисел типа number:

JavaScript
console.log(10 / 0);  // Infinityconsole.log(-10 / 0); // -Infinityconsole.log(0 / 0);   // NaN​

Исключение автоматически не возникает. Поэтому результат расчёта может потребовать проверки.

У bigint свои правила: деление отбрасывает дробную часть к нулю, а деление на 0n вызывает ошибку. Смешивать number и bigint в обычной арифметике тоже нельзя без явного преобразования:

JavaScript
console.log(7n / 2n); // 3n​// console.log(7n / 0n); // RangeError.// console.log(7n + 2);  // TypeError.​

Почему 0.1 + 0.2 не равно ровно 0.3

JavaScript
console.log(0.1 + 0.2);         // 0.30000000000000004console.log(0.1 + 0.2 === 0.3); // false​

Обычные числа JavaScript используют двоичное представление с ограниченной точностью. Некоторые десятичные дроби невозможно сохранить в нём точно — примерно как невозможно записать 1 / 3 конечным количеством десятичных знаков.

Это не случайная поломка калькулятора. Это свойство представления чисел.

В простых денежных расчётах полезно хранить целые копейки:

JavaScript
const firstPriceKopecks = 10;const secondPriceKopecks = 20;const totalKopecks = firstPriceKopecks + secondPriceKopecks;​console.log(totalKopecks);     // 30console.log(totalKopecks / 100); // 0.3​

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

toFixed удобно применять для отображения, но он возвращает строку:

JavaScript
const displayValue = (0.1 + 0.2).toFixed(2);​console.log(displayValue);        // 0.30console.log(typeof displayValue); // string​

11. Присваивание, инкремент и декремент

Мы уже использовали =. У присваивания есть сокращённые формы:

Короткая запись Для обычной переменной означает
total += 100 total = total + 100
total -= 100 total = total - 100
total *= 2 total = total * 2
total /= 2 total = total / 2
total %= 3 total = total % 3
total **= 2 total = total ** 2
JavaScript
let wallet = 1000;​wallet -= 250;wallet += 100;​console.log(wallet); // 850​

Это похоже на операции по счёту: списать сумму, затем пополнить баланс.

+= сохраняет особенности обычного плюса:

JavaScript
let title = "Заказ";title += " оформлен";​console.log(title); // Заказ оформлен​let amount = "100";amount += 50;​console.log(amount); // 10050 (строка)​

Инкремент ++ и декремент --

Эти операторы увеличивают или уменьшают значение на единицу:

JavaScript
let likes = 10;​likes++;console.log(likes); // 11​likes--;console.log(likes); // 10​

Есть две формы, и они отличаются значением самого выражения:

JavaScript
let firstCounter = 5;const oldValue = firstCounter++;​console.log(oldValue);     // 5console.log(firstCounter); // 6​let secondCounter = 5;const newValue = ++secondCounter;​console.log(newValue);      // 6console.log(secondCounter); // 6​

counter++ возвращает значение до увеличения. ++counter возвращает значение после увеличения. В обоих случаях переменная увеличивается уже при выполнении оператора — постфиксная форма не откладывает изменение до следующей строки.

Аналогия — электронная очередь. Один терминал сначала печатает текущий номер и затем переключает счётчик. Другой сначала переключает счётчик и печатает новый номер.

Пока вы учитесь, не прячьте несколько таких изменений внутрь большого выражения. Отдельная строка counter += 1 часто понятнее хитроумной комбинации плюсов.

12. Сравнения: задаём программе вопросы

Арифметика помогает получить число. Сравнение помогает получить ответ на вопрос: «Хватит ли денег?», «Есть ли товар на складе?», «Совпадает ли введённый код с ожидаемым?».

Результат сравнения — true или false.

Оператор Вопрос Пример Результат
> Больше? 10 > 5 true
< Меньше? 10 < 5 false
>= Больше или равно? 10 >= 10 true
<= Меньше или равно? 8 <= 10 true
=== Строго равно? 10 === 10 true
!== Строго не равно? 10 !== 5 true
== Равно с возможным приведением типов? 10 == "10" true
!= Не равно с возможным приведением типов? 10 != "10" false

Почему обычно стоит выбирать ===

JavaScript
console.log(5 === 5);     // trueconsole.log(5 === "5");   // falseconsole.log(5 == "5");    // trueconsole.log(0 == false);  // trueconsole.log(0 === false); // false​

Строгое сравнение не приводит операнды к одному типу. Число 5 и строка "5" отличаются, поэтому результат — false.

Нестрогое сравнение использует дополнительные правила преобразования. Это не обязательно ошибка, но новичку гораздо проще рассуждать о коде, который не меняет типы незаметно.

Представьте проверку билетов. === смотрит и на содержание, и на вид предъявленного значения. == в некоторых случаях соглашается сначала преобразовать предъявленное. Иногда это удобно, но правила такого «согласования» нужно хорошо знать.

Практический подход: явно преобразовать данные и затем использовать === или !==.

JavaScript
const quantityFromInput = "3";const quantity = Number(quantityFromInput);​console.log(quantity === 3); // true​

Строки сравниваются не как числа

JavaScript
console.log("20" > "100"); // trueconsole.log(20 > 100);     // false​

Когда оба операнда — строки, сравнение идёт по их последовательностям кодовых единиц UTF-16, а не по числовому смыслу текста. Для показанных цифр уже первый символ "2" оказывается больше "1".

Для сравнения числового ввода сначала получите числа:

JavaScript
console.log(Number("20") > Number("100")); // false​

Такое строковое сравнение также не заменяет языковые правила сортировки слов. Для сортировки имён с учётом языка существуют отдельные инструменты.

Объекты сравниваются по идентичности

JavaScript
const firstProduct = { price: 100 };const secondProduct = { price: 100 };const sameProduct = firstProduct;​console.log(firstProduct === secondProduct); // falseconsole.log(firstProduct === sameProduct);   // true​

Два одинаково заполненных объекта — всё равно два разных объекта. Это как два одинаковых чемодана: одинаковое содержимое не делает их одним чемоданом.

Нельзя писать интервалы как в математике

Намеренно неправильный пример:

JavaScript
const age = 70;​console.log(18 <= age <= 65); // true — но это не проверка интервала!​

Сначала вычисляется 18 <= 70, получается true. Затем true <= 65 приводит true к 1, и выходит 1 <= 65, то есть снова true.

Нужно соединить две отдельные проверки через логическое «И»:

JavaScript
const age = 70;​console.log(age >= 18 && age <= 65); // false​

13. Логические операторы

Логические операторы объединяют условия. Представим, что вы организуете мероприятие:

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

В JavaScript это &&, || и !.

Логическое «И»: &&

JavaScript
const hasTicket = true;const isEntranceOpen = false;​const canEnter = hasTicket && isEntranceOpen;​console.log(canEnter); // false​

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

Логическое «ИЛИ»: ||

JavaScript
const hasPromoCode = false;const hasClubCard = true;​const hasDiscount = hasPromoCode || hasClubCard;​console.log(hasDiscount); // true​

Достаточно хотя бы одного выполненного условия. Это включающее «или»: если и промокод, и карта есть одновременно, результат тоже true.

Логическое «НЕ»: !

JavaScript
const isLoading = false;​console.log(!isLoading); // true​

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

Таблица для двух логических значений

a b a && b a || b
true true true true
true false false true
false true false true
false false false false

Truthy и falsy: не только true и false

В условии можно использовать не только логический тип. JavaScript интерпретирует значения как истинные (truthy) или ложные (falsy).

Основные falsy-значения:

  • false;
  • 0 и -0;
  • 0n;
  • пустая строка "";
  • null;
  • undefined;
  • NaN.

Остальные обычные значения — truthy. Есть специальное историческое браузерное исключение document.all; в обычных прикладных проверках оно не нужно.

Особенно полезно запомнить:

JavaScript
console.log(Boolean(""));      // falseconsole.log(Boolean("0"));     // trueconsole.log(Boolean("false")); // trueconsole.log(Boolean(" "));    // trueconsole.log(Boolean([]));      // trueconsole.log(Boolean({}));      // true​

Непустая строка "false" не становится ложной только из-за написанного в ней слова. Пустой массив и пустой объект тоже truthy.

Аналогия: запечатанный конверт считается существующим независимо от того, есть ли внутри письмо. Проверка «конверт есть?» не отвечает на вопрос «в нём что-нибудь написано?».

Чтобы проверить непустой массив, спрашивайте о его длине:

JavaScript
const cart = [];​console.log(Boolean(cart));  // trueconsole.log(cart.length > 0); // false​

Двойное отрицание !!value даёт логическое значение. Например, !!"Кофе" — true. По смыслу это преобразование, как Boolean(value), но полная запись часто понятнее начинающему читателю.

Важный поворот: && и || возвращают операнды

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

|| возвращает первый truthy-операнд, а если такого нет — последний операнд:

JavaScript
console.log("" || "Гость");      // Гостьconsole.log("Анна" || "Гость");  // Аннаconsole.log(0 || null);          // null​

&& возвращает первый falsy-операнд, а если все truthy — последний операнд:

JavaScript
console.log("Анна" && "Казань"); // Казаньconsole.log(0 && "Казань");      // 0console.log(true && 100);        // 100​

Они проверяют логическую интерпретацию значений, но возвращают сами значения. Это одна из самых полезных особенностей JavaScript — и одна из самых частых причин удивления.

Короткое замыкание: когда дальше вычислять незачем

Если && встретил falsy-значение, дальше он не вычисляет. Если || встретил truthy-значение, дальше тоже не вычисляет.

JavaScript
let checksCount = 0;​false && (checksCount += 1);true || (checksCount += 1);​console.log(checksCount); // 0​

В обеих строках правая часть не выполнилась. Результат уже был понятен по левой части.

Это как проходная с несколькими условиями. Если вход закрыт для всех, охраннику не нужно проверять ваш билет для принятия решения о входе.

Так можно защитить обращение к свойству:

JavaScript
const user = null;​const canSendEmail = user !== null && user.email !== undefined;​console.log(canSendEmail); // false​

Мы сначала проверили, что user не равен null. Правая часть не выполнилась, поэтому попытки прочитать user.email не было. Эта конкретная проверка рассчитана на null или объект, а не на все возможные типы входных данных.

Не превращайте короткое замыкание в головоломку с множеством побочных действий. Иногда обычный if лучше показывает намерение.

14. ??, ?. и логическое присваивание

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

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

Допустим, настройка громкости может быть равна нулю. Пользователь специально выключил звук. Если применить ||, программа неожиданно вернёт громкость по умолчанию:

JavaScript
const savedVolume = 0;​console.log(savedVolume || 50); // 50console.log(savedVolume ?? 50); // 0​

|| выбирает правую часть при любом falsy-значении слева. ?? делает это только для null и undefined.

JavaScript
console.log(null ?? "Не указано");      // Не указаноconsole.log(undefined ?? "Не указано"); // Не указаноconsole.log(0 ?? 100);                  // 0console.log(false ?? true);             // falseconsole.log("" ?? "Гость");             // пустая строкаconsole.log(NaN ?? 100);                // NaN​

Аналогия: в анкете есть ответ «0 детей». ?? понимает, что ответ получен. || при такой обработке считает ноль поводом подставить запасной вариант.

Ни один из операторов не «лучше всегда». Если пустая строка должна заменяться на "Гость", || может быть уместен. Если пустая строка — допустимая настройка, пригодится ??.

?? тоже использует короткое замыкание: правую часть вычисляет только при null или undefined слева.

?.: безопасно продолжить цепочку доступа

JavaScript
const user = {  name: "Анна",  address: null};​const city = user.address?.city ?? "Город не указан";​console.log(city); // Город не указан​

Если user.address равен null или undefined, необязательная цепочка ?. возвращает undefined вместо ошибки доступа к следующему свойству. После этого ?? подставляет текст.

Если сам user тоже может отсутствовать, защитите и этот уровень:

JavaScript
const user = null;const city = user?.address?.city ?? "Город не указан";​console.log(city); // Город не указан​

Но ?. — не универсальный подавитель ошибок. Корневая переменная должна существовать:

JavaScript
// missingUser?.name; // ReferenceError, если missingUser не объявлена.​

И отдельно: ?. реагирует только на null и undefined, а не на любое falsy-значение.

||=, &&= и ??=

Эти операторы выполняют присваивание только при определённом условии:

Оператор Когда присвоит правую часть
value ||= fallback Если текущее значение falsy
value &&= replacement Если текущее значение truthy
value ??= fallback Если текущее значение — null или undefined
JavaScript
let nickname = "";nickname ||= "Гость";​let volume = 0;volume ??= 50;​let status = "Черновик";status &&= "Готов к проверке";​console.log(nickname); // Гостьconsole.log(volume);   // 0console.log(status);   // Готов к проверке​

Запоминать их все сразу необязательно. Сначала поймите базовые ||, && и ?? — после этого сокращённые записи становятся естественными.

15. Тернарный оператор

Иногда нужно выбрать одно из двух значений по условию. Например, для заказа от 3000 рублей доставка бесплатна, а для остальных стоит 300 рублей.

Форма записи:

Код
условие ? значениеЕслиИстина : значениеЕслиЛожь​

Рабочий пример:

JavaScript
const orderTotal = 3500;const deliveryPrice = orderTotal >= 3000 ? 0 : 300;​console.log(deliveryPrice); // 0​

Читаем слева направо: «Сумма не меньше 3000? Тогда 0. Иначе 300».

Это как развилка с указателем: условие выбирает одну из двух дорог. Вычисляется только выбранная ветка.

То же решение через if

if выполняет блок кода, если условие truthy, а else — альтернативный блок:

JavaScript
const orderTotal = 3500;let deliveryPrice;​if (orderTotal >= 3000) {  deliveryPrice = 0;} else {  deliveryPrice = 300;}​console.log(deliveryPrice); // 0​

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

Полезный пример для интерфейса

JavaScript
const stockCount = 5;const buttonText = stockCount > 0 ? "Добавить в корзину" : "Нет в наличии";​console.log(buttonText); // Добавить в корзину​

Не стоит строить длинную лестницу из вложенных ? и :. Экономия строк не должна превращать чтение программы в разбор ребуса.

16. Приоритет и порядок вычислений

Как и в математике, разные операторы имеют разный приоритет:

JavaScript
console.log(2 + 3 * 4);   // 14console.log((2 + 3) * 4); // 20​

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

Компактная карта приоритетов

Ниже — не полная таблица языка, а ориентир для операторов из статьи, от более высокого приоритета к более низкому:

Уровень Примеры
Явная группировка (a + b)
Доступ к свойствам и вызовы user.name, user?.name, Number(value)
Постфиксное изменение value++, value--
Унарные операции и префиксное изменение !value, typeof value, ++value
Возведение в степень **
Умножение, деление, остаток *, /, %
Сложение, вычитание +, -
Отношения <, >, <=, >=
Равенство ===, !==, ==, !=
Логическое «И» &&
Логическое «ИЛИ» и nullish coalescing ||, ??
Условный выбор ? :
Присваивание =, +=, ??= и другие

У ** есть уже рассмотренное синтаксическое ограничение с унарным минусом слева. Поэтому (-3) ** 2 и -(3 ** 2) допустимы, а -3 ** 2 — нет.

Приоритет логических операторов

JavaScript
console.log(true || false && false);   // trueconsole.log((true || false) && false); // false​

&& имеет более высокий приоритет, чем ||. Первая строка группируется как true || (false && false). Из-за короткого замыкания правая часть || вообще не вычисляется.

Вот зачем различать два понятия:

  • Приоритет определяет, как выражение сгруппировано.
  • Порядок вычислений определяет, какие части и когда действительно выполнятся.

Высокий приоритет внутри пропущенной ветки не заставляет эту ветку выполняться.

Особое правило для ??

JavaScript запрещает напрямую смешивать ?? с || или && без скобок:

JavaScript
const savedName = null;​// const name = savedName ?? "" || "Гость"; // SyntaxError.​const name = (savedName ?? "") || "Гость";​console.log(name); // Гость​

Скобки здесь обязательны, а не просто желательны.

Ассоциативность: как группируются одинаковые операторы

Вычитание группируется слева направо:

JavaScript
console.log(10 - 3 - 2);   // 5: (10 - 3) - 2console.log(10 - (3 - 2)); // 9​

А возведение в степень — справа налево:

JavaScript
console.log(2 ** 3 ** 2);   // 512: 2 ** (3 ** 2)console.log((2 ** 3) ** 2); // 64​

Не нужно держать всю таблицу приоритетов в голове. Если выражение заставляет остановиться и пересчитать правила, добавьте скобки или вынесите часть расчёта в переменную с понятным именем.

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

17. Мини-проект: калькулятор заказа

Теперь соберём изученное в одну программу. Она не будет показывать красивую корзину на странице — зато полностью рассчитает заказ и выведет понятный итог в консоль.

Условия задачи

Наш магазин продаёт настольные лампы. Действуют правила:

  1. Одна лампа стоит 1490 рублей.
  2. Количество поступает строкой, как из поля формы.
  3. Можно заказать от 1 до 10 ламп, только целое количество.
  4. Активный промокод даёт скидку 10% на товары.
  5. При стоимости товаров после скидки от 4000 рублей доставка бесплатна. Иначе — 350 рублей.
  6. Если имя не введено или состоит из пробелов, обращаемся к покупателю «Гость».
  7. Заказ можно оформить, если на балансе достаточно денег.

Деньги будем хранить в копейках. Правило округления скидки в этом учебном примере — Math.round до целой копейки. На практике правило округления задаётся требованиями конкретного продукта.

Полный код

JavaScript
"use strict";​// 1. Входные данные: их удобно менять для экспериментов.const customerNameInput = "  Анна  ";const quantityInput = "3";const hasPromoCode = true;const balanceKopecks = 500_000;​// 2. Настройки магазина.const productName = "Настольная лампа";const productPriceKopecks = 149_000;const deliveryFeeKopecks = 35_000;const freeDeliveryThresholdKopecks = 400_000;const maxQuantity = 10;​// 3. Подготовка и проверка количества.const normalizedQuantityInput = quantityInput.trim();const quantity = Number(normalizedQuantityInput);​const isQuantityValid =  normalizedQuantityInput !== "" &&  Number.isInteger(quantity) &&  quantity >= 1 &&  quantity <= maxQuantity;​if (!isQuantityValid) {  console.log(`Ошибка: введите целое количество от 1 до ${maxQuantity}.`);} else {  // 4. Подготовка имени.  const customerName = customerNameInput.trim() || "Гость";​  // 5. Стоимость товаров и скидка.  const subtotalKopecks = productPriceKopecks * quantity;  const discountPercent = hasPromoCode ? 10 : 0;  const discountKopecks = Math.round(    subtotalKopecks * discountPercent / 100  );  const goodsTotalKopecks = subtotalKopecks - discountKopecks;​  // 6. Доставка зависит от суммы после скидки.  const isDeliveryFree = goodsTotalKopecks >= freeDeliveryThresholdKopecks;  const deliveryKopecks = isDeliveryFree ? 0 : deliveryFeeKopecks;  const totalKopecks = goodsTotalKopecks + deliveryKopecks;​  // 7. Проверка возможности оплатить.  const canPay = balanceKopecks >= totalKopecks;  const missingKopecks = Math.max(totalKopecks - balanceKopecks, 0);  const paymentMessage = canPay    ? "Средств достаточно. Заказ можно оформить."    : `Не хватает: ${(missingKopecks / 100).toFixed(2)} ₽`;​  // 8. Вывод результата. Форматирование не меняет исходные суммы.  console.log(`Покупатель: ${customerName}`);  console.log(`Товар: ${productName}`);  console.log(`Количество: ${quantity}`);  console.log(`До скидки: ${(subtotalKopecks / 100).toFixed(2)} ₽`);  console.log(`Скидка: ${(discountKopecks / 100).toFixed(2)} ₽`);  console.log(`Доставка: ${(deliveryKopecks / 100).toFixed(2)} ₽`);  console.log(`Итого: ${(totalKopecks / 100).toFixed(2)} ₽`);  console.log(paymentMessage);}​

Ожидаемый вывод:

Код
Покупатель: АннаТовар: Настольная лампаКоличество: 3До скидки: 4470.00 ₽Скидка: 447.00 ₽Доставка: 0.00 ₽Итого: 4023.00 ₽Средств достаточно. Заказ можно оформить.​

Разбираем программу по смыслу

Подготовка ввода. Метод .trim() возвращает строку без пробелов по краям. Исходная строка не изменяется. Из " Анна " получается "Анна", а из строки пробелов — "".

Проверка количества. Мы отдельно проверяем, что ввод непустой, что результат — целое число и что он входит в допустимый диапазон. Number.isInteger возвращает false также для NaN и бесконечности, поэтому в данном условии отдельная проверка Number.isFinite не требуется.

Расчёт. Умножение даёт исходную сумму, тернарный оператор выбирает процент скидки, вычитание даёт сумму после скидки, сравнение определяет бесплатную доставку.

Баланс. Math.max(a, b) выбирает большее значение. Здесь он не позволяет вывести отрицательную «нехватку денег»: если денег достаточно, нехватка равна нулю.

Отображение. Только на последнем шаге делим копейки на сто и превращаем сумму в строку с двумя знаками после точки. Исходные переменные с копейками остаются числами.

Почему почти везде const?

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

Не нужно искусственно добавлять let, чтобы программа выглядела «более программной». Каждый новый осмысленный результат вполне может получить отдельное имя.

Эксперименты

Меняйте исходные данные по одному параметру. Остальные оставляйте как в полном примере:

Изменение Что должно получиться
quantityInput = "1" 1341 ₽ за товар после скидки + 350 ₽ доставка = 1691 ₽
quantityInput = "0" Ошибка количества
quantityInput = "2.5" Ошибка: количество не целое
quantityInput = " " Ошибка: пустой ввод
quantityInput = "кофе" Ошибка: результат преобразования — NaN
hasPromoCode = false Сумма 4470 ₽, скидка 0 ₽, доставка бесплатная
balanceKopecks = 300_000 Не хватает 1023 ₽
customerNameInput = " " Покупатель: Гость

Граница учебного примера: Number принимает некоторые дополнительные числовые форматы, например "3e0" как 3. Если форма должна разрешать только десятичные цифры, понадобится отдельная проверка формата. Кроме того, входные имена и количество здесь предполагаются строками, а настройки — заранее корректными. Код ничего не списывает и не отправляет на сервер. В настоящем магазине цену, скидку, остатки и возможность оплаты обязательно проверяют на сервере: пользователь может изменить клиентский JavaScript.

18. Типичные ошибки и приёмы отладки

Новичок часто думает: «Я допустил ошибку, значит, не понимаю программирование». На практике программирование включает постоянный поиск ошибок. Умение спокойно сузить проблему полезнее способности с первого раза написать идеальную строку.

Ошибка 1. Перепутать имя переменной со строкой

JavaScript
const userName = "Анна";​console.log(userName);   // Аннаconsole.log("userName"); // userName​

Без кавычек мы читаем значение переменной. В кавычках — выводим буквальный текст.

Ошибка 2. Использовать имя с другим регистром

JavaScript
const productPrice = 500;​console.log(productPrice); // 500​// console.log(productprice); // ReferenceError.​

Проверяйте регистр и опечатки. Для языка это разные имена.

Ошибка 3. Написать = вместо ===

Намеренно неправильная логика:

JavaScript
let role = "user";​if (role = "admin") {  console.log("Доступ разрешён"); // Выполнится!}​console.log(role); // admin​

Мы не проверили роль, а присвоили новую. Выражение присваивания вернуло строку "admin", которая truthy. Поэтому ветка выполнилась.

Правильная проверка:

JavaScript
const role = "user";​if (role === "admin") {  console.log("Доступ разрешён");} else {  console.log("Доступ запрещён"); // Доступ запрещён}​

Это демонстрация условия, не полноценная система прав доступа. Настоящая проверка доступа должна выполняться на сервере.

Ошибка 4. Сложить числа, которые оказались строками

JavaScript
const firstValue = "10";const secondValue = "20";​console.log(firstValue + secondValue);                 // 1020console.log(Number(firstValue) + Number(secondValue)); // 30​

Если сумма похожа на склеенные цифры, первым делом проверьте типы.

Ошибка 5. Потерять правильный ноль из-за ||

JavaScript
const savedDiscount = 0;​const wrongDiscount = savedDiscount || 10;const correctDiscount = savedDiscount ?? 10;​console.log(wrongDiscount);   // 10console.log(correctDiscount); // 0​

Спросите себя: нужно заменить любое falsy-значение или только отсутствующее?

Ошибка 6. Проверять NaN через равенство

JavaScript
const amount = Number("ошибка");​console.log(amount === NaN);       // falseconsole.log(Number.isNaN(amount)); // true​

Ошибка 7. Думать, что ошибка всегда останавливает программу

Склеивание строк вместо сложения чисел не вызывает исключение. Программа может успешно завершиться и выдать неправильную для задачи сумму.

Полезно различать:

Вид проблемы Пример Что это означает
SyntaxError const price; Запись не соответствует синтаксису
ReferenceError Обращение к недоступному имени Переменную нельзя получить в этом месте
TypeError Переприсваивание const Операция недопустима в данном случае
Логическая ошибка "10" + "20" вместо суммы Код выполняется, но решает задачу неправильно

Небольшой алгоритм отладки

  1. Сформулируйте ожидаемый результат конкретным числом или значением.
  2. Посмотрите, что фактически получилось.
  3. Выведите входные данные вместе с их типами.
  4. Разбейте большое выражение на промежуточные переменные.
  5. Проверьте крайние случаи: ноль, пустую строку, границу диапазона, отсутствие данных.

Например:

JavaScript
const input = "250";​console.log("Вход:", input);console.log("Тип входа:", typeof input);​const number = Number(input);​console.log("После преобразования:", number);console.log("Тип результата:", typeof number);console.log("Конечное число:", Number.isFinite(number));​

Аналогия — поиск протечки. Если последовательно проверять участки трубы, найти место проблемы проще, чем смотреть только на лужу в конце.

19. Практические задания

Сначала решите задания без подсказок. Для задач на предсказание запишите не только значение, но и его тип. Затем запустите код и сравните результат с предположением.

Задание 1. Визитка

Создайте переменные с именем, городом и годом начала обучения. Выведите одну строку вида: Меня зовут Анна. Я из Казани. Изучаю JavaScript с 2026 года. Используйте шаблонный литерал.

Задание 2. Выбор объявления

Что выбрать — let или const — для каждого случая? Объясните почему.

  • Название магазина, которое не переприсваивается.
  • Счётчик кликов, который увеличивается.
  • Массив товаров, в который добавляют элементы, но который не заменяют другим массивом.

Задание 3. Копия цены

Предскажите вывод:

JavaScript
let price = 100;const oldPrice = price;​price += 50;​console.log(oldPrice);console.log(price);​

Задание 4. Скидка

Товар стоит 2400 рублей. Скидка — 15%. Рассчитайте размер скидки и итоговую цену в отдельных переменных.

Задание 5. Минуты и секунды

Есть 367 секунд. Получите количество полных минут и оставшихся секунд. Ожидаемый результат: 6 мин. 7 сек.

Задание 6. Числа или строки?

Предскажите значения и типы результатов:

JavaScript
console.log("10" + 5);console.log("10" - 5);console.log(2 + 3 + "4");console.log("2" + 3 + 4);console.log(Number(""));​

Задание 7. Проверка возраста

Возраст приходит строкой "21". Преобразуйте его в число и проверьте, попадает ли он в диапазон от 18 до 65 включительно.

Задание 8. Доступ к мероприятию

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

Задание 9. Имя по умолчанию

В переменной nameInput находится строка из трёх пробелов. Получите имя для отображения: если после удаления пробелов по краям строка пуста, используйте "Гость".

Задание 10. Сохранить ноль

Значение savedVolume равно 0. Создайте volume, которое получает 50 только при null или undefined. Ноль должен сохраниться.

Задание 11. Счётчики

Предскажите результат:

JavaScript
let counter = 4;​const first = counter++;const second = ++counter;​console.log(first, second, counter);​

Задание 12. Общий объект

Предскажите вывод и объясните его:

JavaScript
const first = { score: 10 };const second = first;​second.score += 5;​console.log(first.score);console.log(first === second);​

Задание 13. Проверка количества

Количество товара приходит строкой. Разрешены только непустые значения, которые после преобразования являются целыми числами от 1 до 20. Напишите проверку и испытайте её на "5", "0", "2.5", "abc", " ".

Задание 14. Бесплатная доставка

Сумма товаров — 2800 рублей. Доставка бесплатна от 3000 рублей или при наличии подписки. В остальных случаях она стоит 300 рублей. Используйте логический и тернарный операторы.

Задание 15. Почините расчёт

В примере три независимые ошибки в логике. Должно получиться: количество 2, сумма 1000, скидка 0, проверка количества true.

JavaScript
const price = "500";const quantity = "2";const discountFromSettings = 0;​const total = price + quantity;const discount = discountFromSettings || 10;const isQuantityCorrect = quantity === 2;​console.log(total, discount, isQuantityCorrect);​

20. Ответы и объяснения

Решение 1. Визитка

JavaScript
const name = "Анна";const city = "Казань";const learningStartYear = 2026;​console.log(  `Меня зовут ${name}. Мой город — ${city}. ` +  `Изучаю JavaScript с ${learningStartYear} года.`);​

Формулировку про город немного изменили, чтобы не заниматься программным склонением названия. Внутри ${...} можно подставлять не только строки, но и числа.

Решение 2. Выбор объявления

  • Название магазина — const: переприсваивание не требуется.
  • Счётчик — let: значение будет меняться.
  • Массив — const: добавление элементов не заменяет саму ссылку на массив.

Решение 3. Копия цены

Программа выведет 100, затем 150. В oldPrice сохранилось числовое значение на момент присваивания; автоматической связи с price нет.

Решение 4. Скидка

JavaScript
const price = 2400;const discountPercent = 15;const discountAmount = price * discountPercent / 100;const finalPrice = price - discountAmount;​console.log(discountAmount); // 360console.log(finalPrice);     // 2040​

Решение 5. Минуты и секунды

JavaScript
const totalSeconds = 367;const minutes = Math.floor(totalSeconds / 60);const seconds = totalSeconds % 60;​console.log(`${minutes} мин. ${seconds} сек.`); // 6 мин. 7 сек.​

Решение 6. Числа или строки?

Выражение Значение Тип
"10" + 5 "105" string
"10" - 5 5 number
2 + 3 + "4" "54" string
"2" + 3 + 4 "234" string
Number("") 0 number

В третьей строке сначала складываются два числа. В четвёртой склеивание начинается с первого оператора.

Решение 7. Проверка возраста

JavaScript
const ageInput = "21";const age = Number(ageInput);const isAgeSuitable = age >= 18 && age <= 65;​console.log(isAgeSuitable); // true​

Для полноценной формы добавьте требования к формату и целочисленности возраста. Здесь исходная строка задана условием.

Решение 8. Доступ к мероприятию

JavaScript
const isEventOpen = true;const hasTicket = false;const isOnGuestList = true;​const canEnter = isEventOpen && (hasTicket || isOnGuestList);​console.log(canEnter); // true​

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

Если написать isEventOpen && hasTicket || isOnGuestList, человек из списка получит true даже при закрытом мероприятии. Это уже другое правило.

Решение 9. Имя по умолчанию

JavaScript
const nameInput = "   ";const displayName = nameInput.trim() || "Гость";​console.log(displayName); // Гость​

Здесь || выбран намеренно: пустая строка должна заменяться.

Решение 10. Сохранить ноль

JavaScript
const savedVolume = 0;const volume = savedVolume ?? 50;​console.log(volume); // 0​

Решение 11. Счётчики

Результат — 4 6 6. После counter++ переменная становится равной 5, но в first записывается прежнее значение 4. Затем ++counter увеличивает значение до 6 и возвращает 6.

Решение 12. Общий объект

Результат — 15 и true. Переменные указывают на один объект, поэтому изменение свойства видно через обе переменные.

Решение 13. Проверка количества

JavaScript
const input = "5";const normalizedInput = input.trim();const quantity = Number(normalizedInput);​const isValid =  normalizedInput !== "" &&  Number.isInteger(quantity) &&  quantity >= 1 &&  quantity <= 20;​console.log(isValid); // true​

При замене input на "0", "2.5", "abc" или " " результат будет false.

Решение 14. Бесплатная доставка

JavaScript
const goodsTotal = 2800;const hasSubscription = true;​const isDeliveryFree = goodsTotal >= 3000 || hasSubscription;const deliveryPrice = isDeliveryFree ? 0 : 300;​console.log(deliveryPrice); // 0​

Промежуточная переменная isDeliveryFree делает условие понятнее и позволяет отдельно проверить его в консоли.

Решение 15. Исправленный расчёт

JavaScript
const priceInput = "500";const quantityInput = "2";const discountFromSettings = 0;​const price = Number(priceInput);const quantity = Number(quantityInput);​const total = price * quantity;const discount = discountFromSettings ?? 10;const isQuantityCorrect = quantity === 2;​console.log(quantity); // 2console.log(total); // 1000console.log(discount); // 0console.log(isQuantityCorrect); // true​

Мы выбрали умножение для стоимости заказа, явно преобразовали входные строки и сохранили допустимую нулевую скидку с помощью ??.

21. Шпаргалка и дальнейшие шаги

Переменные и типы

Нужно сделать Что использовать
Объявить переменную без будущего переприсваивания const price = 100
Объявить изменяемый счётчик let count = 0
Узнать тип typeof value
Преобразовать строку в число Number(value)
Получить строку String(value)
Получить логическое значение Boolean(value)
Проверить NaN Number.isNaN(value)
Проверить конечное число Number.isFinite(value)
Проверить целое число Number.isInteger(value)
Подставить значение в текст Обратные кавычки и ${value}

Операторы

Нужно сделать Запись
Присвоить значение value = 10
Прибавить к переменной value += 10
Сравнить без приведения типов a === b
Проверить неравенство без приведения типов a !== b
Потребовать оба условия a && b
Потребовать хотя бы одно условие a || b
Получить логическое отрицание !value
Подставить запасное значение при null или undefined value ?? fallback
Прочитать свойство, учитывая возможный null/undefined слева object?.property
Выбрать одно из двух значений condition ? first : second
Получить остаток a % b
Возвести в степень a ** b

Что ещё есть в языке

Мы подробно разобрали основу, но не все операторы JavaScript. Позже вам встретятся in, instanceof, delete, new, побитовые операторы и другие возможности.

Например, & и | работают с битовым представлением чисел и не являются заменой логическим && и ||. Если случайно пропустить один символ в условии, смысл программы изменится.

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

Семь привычек, которые сэкономят много времени

  1. Выбирайте const по умолчанию, let — для переприсваивания.
  2. Называйте переменную по смыслу и при необходимости указывайте единицы измерения.
  3. Преобразуйте входные данные явно и проверяйте их отдельно от расчёта.
  4. Начинайте со строгих сравнений === и !==.
  5. Помните, что && и || возвращают операнды, а не обязательно булевы значения.
  6. Различайте ноль, пустую строку и отсутствие значения.
  7. Выбирайте читаемую запись, а не минимальное количество символов.

Что изучать дальше

Логичное продолжение — подробнее разобрать if и switch, затем циклы, функции, массивы и объекты. После этого можно перейти к DOM — работе с элементами страницы, событиям кнопок и форм.

Например, наш калькулятор заказа уже содержит вычислительную основу. Следующий шаг — получать количество из поля, пересчитывать итог при изменении и выводить результат рядом с кнопкой заказа.

Но фундамент остаётся тем же:

  • переменные дают данным имена;
  • типы определяют характер значений;
  • операторы выполняют действия;
  • условия помогают выбрать дальнейшее поведение.

Программирование начинается не с умения писать сложные конструкции. Оно начинается с привычки задавать точные вопросы: «Какое значение здесь находится? Какой у него тип? Что сделает этот оператор? Что должно произойти на границе?».

Если вы можете объяснить своими словами, почему "5" + 2 превращается в "52", почему 0 ?? 100 остаётся нулём и почему изменение свойства объекта разрешено при const, у вас уже есть хорошая опора для следующего шага.

Сообщить об ошибке в статье

Рекомендации редакции

Другие публикации из этого раздела.

Новые материалы

Получайте практические разборы без информационного шума

Одна общая рассылка о новых статьях и инструментах. Адрес будет активироваться только после подтверждения.

Подписка появится после подключения сервиса рассылок и Yandex SmartCaptcha.