Ошибка NaN в консоли при вычислениях через Math чаще всего означает, что в переменную, объявленную через var, попала строка вместо числа — например, значение из поля ввода без преобразования. Проверьте тип данных через typeof до вызова математической функции: если результат "string", сначала примените Number() или parseFloat(). Это самая частая причина «сломанной математики» в скриптах начинающих разработчиков.

В этой статье разберём, как объявлять переменные через var, какие методы предоставляет встроенный объект Math в JavaScript, где возникают типичные ошибки и как писать вычисления, которые не ломаются на граничных значениях. Материал ориентирован на тех, кто только начинает работать с языком или хочет систематизировать базовые знания.

Объявление переменных через var: что нужно знать

Ключевое слово var — исторически первый способ объявления переменных в JavaScript. Переменная создаётся командой var x = 10;, после чего её значение можно менять сколько угодно раз. В отличие от let и const, у var функциональная область видимости: переменная «видна» во всей функции, а не только внутри блока фигурных скобок.

Особенность, о которой часто забывают, — всплытие (hoisting). Объявление через var интерпретатор поднимает в начало функции, поэтому обращение к переменной до строки объявления не вызовет ошибку, а вернёт undefined. С let в том же месте была бы ошибка ReferenceError. Это различие важно при отладке старого кода.

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

💡

var имеет функциональную область видимости и всплывает — в новом коде используйте let и const, но читать var-код нужно уметь.

Объект Math: основные методы

Встроенный объект Math предоставляет набор статических методов и констант для вычислений. Его не нужно создавать через new — все методы вызываются напрямую: Math.round(4.6) вернёт 5. Ниже — наиболее востребованные функции.

  • 🔢 Math.round(x) — округление до ближайшего целого;
  • ⬇️ Math.floor(x) — округление вниз, Math.ceil(x) — вверх;
  • ✂️ Math.trunc(x) — отбрасывание дробной части;
  • 📈 Math.max(a, b, ...) и Math.min(a, b, ...) — поиск крайних значений;
  • 🎲 Math.random() — случайное число от 0 (включительно) до 1 (не включительно);
  • 💪 Math.pow(x, n) или оператор ** — возведение в степень.

Константы тоже доступны из коробки: Math.PI для числа π, Math.E для основания натурального логарифма. Они полезны в геометрических расчётах — например, площадь круга вычисляется как Math.PI r r.

📊 Какой метод Math вы используете чаще всего?
Math.round / floor / ceil
Math.random
Math.max / min
Math.pow и корни

Практические примеры вычислений

Рассмотрим типовую задачу — генерацию случайного целого числа в заданном диапазоне. Комбинация Math.random() с Math.floor() — стандартный приём:

var min = 1;

var max = 10;

var randomInt = Math.floor(Math.random() * (max - min + 1)) + min;

Здесь Math.random() даёт дробь от 0 до 1, умножение растягивает её на нужный диапазон, а Math.floor() отбрасывает дробную часть. Сдвиг на min переносит результат в целевой интервал.

Второй частый сценарий — округление денежных значений до двух знаков. Прямой вызов Math.round(price) не подойдёт: он округляет до целого. Используйте трюк с умножением и делением на 100:

var price = 19.987;

var rounded = Math.round(price * 100) / 100; // 19.99

💡

Для денежных расчётов храните суммы в копейках (целых числах), а делите на 100 только при выводе — это исключает ошибки плавающей точки вида 0.1 + 0.2 !== 0.3.

Типичные ошибки и их диагностика

Главный источник сбоев — неявное приведение типов. Строка "10" в умножении сработает как число, но в сложении даст конкатенацию: "10" + 5 вернёт строку "105", а не 15. Перед математическими операциями явно преобразуйте входные данные.

Вторая группа проблем — погрешности плавающей точки. Выражение 0.1 + 0.2 в JavaScript даёт 0.30000000000000004, это особенность двоичного представления дробей, а не баг языка. Сравнивайте дробные числа с допуском, а не строгим равенством.

СимптомВероятная причинаЧто проверить
Результат NaNСтрока или undefined в вычисленииtypeof всех операндов
"10" + 5 = "105"Конкатенация вместо сложенияЯвное преобразование Number()
0.1 + 0.2 ≠ 0.3Погрешность float64Сравнение с допуском epsilon
undefined до объявленияВсплытие varПорядок строк в функции
Math.max() вернул -InfinityВызов без аргументовПроверка длины массива
⚠️ Внимание: методы Math.max() и Math.min() не принимают массив напрямую. Вызов Math.max([1, 2, 3]) вернёт NaN. Используйте оператор расширения: Math.max(...arr), предварительно убедившись, что массив не пуст.

Пошаговая проверка вычислений в скрипте

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

☑️ Отладка математических вычислений

Выполнено: 0 / 5

Разбивка длинного выражения на промежуточные переменные — приём, который экономит часы отладки. Вместо var result = Math.round((a + b) * c / d); напишите три строки с отдельными переменными и выведите каждую в консоль. Точка сбоя станет видна сразу.

Почему var считается устаревшим

var не имеет блочной области видимости: переменная, объявленная внутри if или цикла, видна во всей функции. Это провоцирует случайные переопределения. let и const, добавленные в стандарте ES2015, ограничены блоком и делают код предсказуемее. const дополнительно запрещает переприсваивание, что помогает отслеживать, какие значения меняются, а какие нет.

Var, let и const: что выбрать в новом коде

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

Что делать, если вы правите легаси-файл, где всё объявлено через var? Менять объявления «вслепую» по всему файлу не стоит: из-за разницы в области видимости и всплытии поведение кода может измениться. Заменяйте точечно, проверяя, что переменная не используется до строки объявления и не переобъявляется в той же функции.

⚠️ Внимание: механическая замена var на let в циклах с асинхронными колбэками меняет результат. С var все колбэки делят одну переменную, с let каждая итерация получает свою копию. Иногда это исправляет баг, а иногда ломает логику, рассчитанную на старое поведение.
💡

Включите в редакторе линтер (например, ESLint с правилом no-var) — он автоматически подсветит все устаревшие объявления и предложит безопасную замену.

Часто задаваемые вопросы

Чем var отличается от let?

У var функциональная область видимости и всплытие с инициализацией undefined. У let — блочная область видимости, а обращение до объявления вызывает ошибку. Повторное объявление одной переменной через var допустимо, через let — нет.

Как округлить число до двух знаков после запятой?

Умножьте на 100, примените Math.round(), затем разделите на 100. Для вывода строки с фиксированным количеством знаков есть метод toFixed(2), но он возвращает строку, а не число.

Почему Math.random() не подходит для паролей?

Math.random() не является криптографически стойким генератором — его последовательность предсказуема. Для токенов и паролей используйте crypto.getRandomValues(), доступный в браузерах и Node.js.

Что вернёт Math.max() без аргументов?

Значение -Infinity. Симметрично Math.min() без аргументов вернёт Infinity. Если вы передаёте данные из массива, который может оказаться пустым, проверяйте его длину заранее.

Можно ли создать экземпляр Math через new?

Нет. Math — не конструктор, а обычный объект с набором статических методов и констант. Все вычисления выполняются прямыми вызовами вида Math.sqrt(25).