Числа в JavaScript: типы, преобразования и операции с примерами
#Основы JavaScript #Синтаксис и типы данных #Операторы и выраженияДля кого эта статья:
- Программисты и разработчики, работающие с JavaScript
- Специалисты по веб-разработке и созданию финансовых приложений
- Люди, изучающие особенности работы с числами и математическими операциями в JavaScript
Каждый программист на JavaScript однажды сталкивается с сюрпризом: 0.1 + 0.2 !== 0.3. Этот маленький парадокс открывает дверь в удивительный мир чисел в JavaScript — со своими правилами, особенностями и неожиданными поворотами. Точность финансовых расчетов, обработка пользовательского ввода, сложные математические операции — всё это требует глубокого понимания числовых типов. Погрузимся в эту тему, чтобы вы больше никогда не попадались на числовые ловушки и могли писать надежный, предсказуемый код. 📊
Числовые типы в JavaScript: Number и BigInt
JavaScript предлагает два основных типа для работы с числами: Number и BigInt. Понимание их особенностей критически важно для правильного проектирования вычислений.
Number — базовый числовой тип, представляющий как целые, так и дробные значения. Он использует 64-битный формат с плавающей точкой (IEEE 754), что позволяет хранить числа в диапазоне от ±5×10<sup>-324</sup> до ±1.8×10<sup>308</sup>.
BigInt — относительно новый тип (представлен в ES2020), способный представлять целые числа произвольной длины. Он решает проблему ограниченного диапазона Number для целых чисел.
| Свойство | Number | BigInt |
|---|---|---|
| Синтаксис создания | 42, 3.14 | 42n, BigInt(42) |
| Поддержка дробных значений | Да | Нет |
| Максимальное безопасное целое | Number.MAX_SAFE_INTEGER (2<sup>53</sup>-1) | Неограниченно |
| Производительность | Высокая | Ниже для больших чисел |
| Поддержка математических операций | Полная | Ограниченная, без смешивания типов |
Number включает несколько специальных значений:
Infinityи-Infinity— представления бесконечностиNaN(Not a Number) — результат неопределенных или невозможных операций0и-0— положительный и отрицательный нули (редко встречаются в практике)
Максим, технический директор финтех-стартапа Мы разрабатывали систему для трейдинговой платформы, и наш код периодически давал странные результаты при расчетах крупных сумм. Оказалось, мы наткнулись на предел безопасных целых чисел в JavaScript. Число 9007199254740992 + 1 давало тот же результат, что и 9007199254740992! Переход на BigInt для операций с крупными суммами полностью решил проблему. Но важно помнить — BigInt и Number не совместимы напрямую в операциях, нужна явная конверсия.
При выборе числового типа руководствуйтесь следующими принципами:
- Используйте Number для большинства обычных вычислений
- Переходите на BigInt, когда требуется работа с целыми числами за пределами ±2<sup>53</sup>
- Учитывайте, что BigInt требует больше ресурсов для простых операций
- Помните о невозможности смешивания типов без явного преобразования
Код для проверки границ числовых типов:
// Демонстрация пределов типа Number
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1); // 9007199254740992
console.log(Number.MAX_SAFE_INTEGER + 2); // 9007199254740992 (ошибка!)
// Использование BigInt для больших чисел
const bigNum = 9007199254740991n;
console.log(bigNum + 1n); // 9007199254740992n
console.log(bigNum + 2n); // 9007199254740993n (корректно!)

Преобразование типов: строки и числа в JavaScript
Преобразование между строками и числами — одна из самых частых операций при разработке на JavaScript. От корректности этих преобразований зависит надежность вашего приложения, особенно при обработке пользовательского ввода. 🔄
JavaScript предлагает несколько способов преобразования строк в числа:
Number()— строгое преобразование с отклонением некорректного форматаparseInt()— извлекает целое число, игнорируя нецифровые символы после первого числаparseFloat()— извлекает число с плавающей точкой- Унарный оператор
+— краткий способ преобразования, эквивалентный Number()
Анна, ведущий разработчик веб-приложений В одном из проектов мы собирали данные через форму, где пользователи вводили числовые значения. Мы использовали простое преобразование через унарный плюс и столкнулись с неожиданной проблемой: во многих странах Европы десятичным разделителем является запятая, а не точка. Когда немецкий пользователь вводил "10,5", наш код преобразовывал это в NaN. Мы решили проблему, используя интернационализированный парсер, заменяющий запятые на точки перед конвертацией. Также мы добавили валидацию на стороне клиента, которая показывала подсказки о правильном формате ввода.
Для преобразования числа в строку также существует несколько методов:
String()— создаёт строковое представление любого значенияtoString()— метод объекта Number с возможностью указания системы счисленияtoFixed()— преобразует число в строку с указанным количеством десятичных знаков- Конкатенация с пустой строкой
num + ""— простой, но менее очевидный способ
| Метод преобразования | Пример | Результат | Особенности |
|---|---|---|---|
| Number() | Number("123.45") | 123.45 | Строгое преобразование, возвращает NaN при ошибке |
| parseInt() | parseInt("123.45", 10) | 123 | Возвращает целое число, требует указания основания |
| parseFloat() | parseFloat("123.45") | 123.45 | Обрабатывает десятичные числа |
| Унарный + | +"123.45" | 123.45 | Краткая запись Number(), часто используется в коде |
| toString() | (123.45).toString() | "123.45" | Можно указать основание системы счисления |
| toFixed() | (123.45).toFixed(1) | "123.5" | Округляет до указанного количества знаков после запятой |
При работе с преобразованиями типов важно помнить о потенциальных ошибках:
// Потенциальные проблемы и их решения
console.log(parseInt("08")); // В старых браузерах: 0 (восьмеричная система)
console.log(parseInt("08", 10)); // 8 (явное указание десятичной системы)
console.log(Number("10,5")); // NaN (запятая вместо точки)
console.log(Number("10.5")); // 10.5
console.log(+""); // 0 (пустая строка преобразуется в ноль)
console.log(+null); // 0 (null преобразуется в ноль)
console.log(+undefined); // NaN
console.log(+"текст"); // NaN
// Правильная обработка пользовательского ввода
function parseUserInput(input) {
// Заменяем запятые на точки для интернационализации
const normalized = input.replace(/,/g, '.');
const num = parseFloat(normalized);
return isNaN(num) ? null : num;
}
console.log(parseUserInput("10,5")); // 10.5
Базовые и расширенные математические операции в JS
JavaScript предоставляет полный набор инструментов для выполнения математических операций — от элементарных арифметических действий до сложных вычислений. Мастерство в использовании этих инструментов позволяет создавать эффективные алгоритмы и точные расчеты. ➗
Базовые арифметические операторы включают:
+(сложение)-(вычитание)*(умножение)/(деление)%(остаток от деления)**(возведение в степень, ES2016+)
Для более сложных математических операций JavaScript предоставляет объект Math, который содержит методы для тригонометрических, логарифмических и других математических функций.
Наиболее часто используемые методы объекта Math:
Math.abs(x)— возвращает абсолютное значение числаMath.ceil(x)— округление вверхMath.floor(x)— округление внизMath.round(x)— округление к ближайшему целомуMath.trunc(x)— удаляет дробную часть (ES2015+)Math.max(...values)— находит максимальное значениеMath.min(...values)— находит минимальное значениеMath.random()— генерирует псевдослучайное число от 0 до 1Math.pow(x, y)— возведение x в степень y (устаревший аналог оператора **)Math.sqrt(x)— квадратный корень числа
Примеры использования базовых операторов:
// Базовые арифметические операции
let sum = 10 + 5; // 15
let difference = 10 – 5; // 5
let product = 10 * 5; // 50
let quotient = 10 / 5; // 2
let remainder = 10 % 3; // 1
let power = 10 ** 2; // 100
// Составные операторы присваивания
let x = 5;
x += 3; // x = 8
x -= 2; // x = 6
x *= 2; // x = 12
x /= 4; // x = 3
// Инкремент и декремент
let y = 5;
let z = y++; // z = 5, y = 6 (постфиксный инкремент)
let a = 5;
let b = ++a; // b = 6, a = 6 (префиксный инкремент)
Примеры использования методов объекта Math:
// Округление и работа с дробями
console.log(Math.round(4.7)); // 5
console.log(Math.round(4.4)); // 4
console.log(Math.ceil(4.4)); // 5
console.log(Math.floor(4.7)); // 4
console.log(Math.trunc(4.7)); // 4
// Поиск минимума и максимума
console.log(Math.min(2, 5, 1, 8, 3)); // 1
console.log(Math.max(2, 5, 1, 8, 3)); // 8
// Генерация случайных чисел
console.log(Math.random()); // случайное число от 0 до <1
// Случайное целое от min до max (включительно)
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max – min + 1)) + min;
}
console.log(getRandomInt(1, 10)); // случайное число от 1 до 10
// Математические функции
console.log(Math.sqrt(16)); // 4 (квадратный корень)
console.log(Math.pow(2, 3)); // 8 (2 в степени 3)
console.log(2 ** 3); // 8 (то же самое с оператором)
console.log(Math.abs(-5)); // 5 (абсолютное значение)
Расширенные математические операции часто требуют особого внимания к точности. JavaScript, как и многие другие языки, использует формат чисел с плавающей точкой, что может приводить к небольшим погрешностям в арифметических операциях:
// Классический пример проблемы с плавающей точкой
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false
// Решение: использование допустимой погрешности (эпсилон)
function areEqual(a, b, epsilon = 0.0001) {
return Math.abs(a – b) < epsilon;
}
console.log(areEqual(0.1 + 0.2, 0.3)); // true
// Альтернативное решение: умножение и деление для избегания дробей
console.log((0.1 * 10 + 0.2 * 10) / 10); // 0.3
Методы работы с числами в JavaScript
JavaScript предоставляет множество методов для эффективной работы с числами, от базового форматирования до специализированных вычислений. Освоение этих методов позволяет создавать более читаемый, поддерживаемый код и избегать распространенных ошибок при числовых операциях. 🧮
Основные методы прототипа Number:
toFixed(n)— форматирует число, используя фиксированное количество цифр после запятойtoPrecision(n)— форматирует число с указанным общим количеством значащих цифрtoString([radix])— преобразует число в строковое представление с возможностью указания основания системы счисленияtoExponential(n)— возвращает строку с числом в экспоненциальной записиtoLocaleString([locales[, options]])— возвращает строку с числом, форматированным согласно языковым настройкам
Статические методы и свойства объекта Number:
Number.isInteger()— проверяет, является ли значение целым числомNumber.isFinite()— определяет, является ли значение конечным числомNumber.isNaN()— проверяет, является ли значение NaNNumber.parseInt()иNumber.parseFloat()— парсят строковое значение в числоNumber.MAX_SAFE_INTEGERиNumber.MIN_SAFE_INTEGER— константы, определяющие границы безопасных целых чиселNumber.EPSILON— наименьшая разница между представимыми числамиNumber.MAX_VALUEиNumber.MIN_VALUE— максимальное и минимальное положительные числа
Примеры использования методов прототипа Number:
// Форматирование чисел с фиксированной точкой
const price = 19.99;
console.log(price.toFixed(0)); // "20"
console.log(price.toFixed(1)); // "20.0"
console.log(price.toFixed(2)); // "19.99"
console.log(price.toFixed(3)); // "19.990"
// Форматирование с определенной точностью
const largeNumber = 1234.56789;
console.log(largeNumber.toPrecision(4)); // "1235"
console.log(largeNumber.toPrecision(7)); // "1234.568"
// Преобразование в различные системы счисления
const decimal = 42;
console.log(decimal.toString()); // "42" (десятичная)
console.log(decimal.toString(2)); // "101010" (двоичная)
console.log(decimal.toString(8)); // "52" (восьмеричная)
console.log(decimal.toString(16)); // "2a" (шестнадцатеричная)
// Локализованное форматирование чисел
const bigNum = 1234567.89;
console.log(bigNum.toLocaleString('en-US')); // "1,234,567.89"
console.log(bigNum.toLocaleString('de-DE')); // "1.234.567,89"
console.log(bigNum.toLocaleString('ru-RU')); // "1 234 567,89"
// Форматирование валюты
console.log(bigNum.toLocaleString('en-US', {
style: 'currency',
currency: 'USD'
})); // "$1,234,567.89"
console.log(bigNum.toLocaleString('de-DE', {
style: 'currency',
currency: 'EUR'
})); // "1.234.567,89 €"
Примеры использования статических методов Number:
// Проверка типов и свойств чисел
console.log(Number.isInteger(42)); // true
console.log(Number.isInteger(42.0)); // true
console.log(Number.isInteger(42.1)); // false
console.log(Number.isFinite(42)); // true
console.log(Number.isFinite(Infinity)); // false
console.log(Number.isFinite(NaN)); // false
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("NaN")); // false (строгая проверка)
console.log(isNaN("NaN")); // true (нестрогая глобальная функция)
// Парсинг чисел
console.log(Number.parseInt("42px", 10)); // 42
console.log(Number.parseFloat("3.14rad")); // 3.14
// Константы и пределы
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
console.log(Number.EPSILON); // 2.220446049250313e-16
console.log(Number.MAX_VALUE); // 1.7976931348623157e+308
console.log(Number.MIN_VALUE); // 5e-324
| Метод | Использование | Сценарий применения |
|---|---|---|
| toFixed() | Отображение финансовых значений | Форматирование цен, расчет налогов |
| toString(16) | Работа с цветами, битовыми операциями | Преобразование RGB в HEX, битовые маски |
| toLocaleString() | Интернационализация приложений | Отображение форматированных чисел для разных регионов |
| Number.isInteger() | Валидация ввода | Проверка корректности количества, возраста и т.д. |
| Number.parseFloat() | Обработка пользовательского ввода | Парсинг значений из полей форм |
Практические советы по работе с методами чисел в JavaScript:
- Всегда используйте
Number.isNaN()вместо глобальной функцииisNaN()для строгой проверки NaN - При работе с пользовательским вводом всегда указывайте радикс (основание системы счисления) для
parseInt:parseInt("08", 10) - Используйте
toLocaleString()для форматирования чисел в пользовательском интерфейсе — это автоматически учтет региональные особенности - Помните о точности
toFixed(): метод округляет результат, что может быть критично для финансовых расчетов - Для сравнения чисел с плавающей точкой используйте
Number.EPSILONв качестве допустимой погрешности
Особенности и ограничения чисел в JavaScript
Понимание особенностей и ограничений чисел в JavaScript критически важно для написания надежного кода. Даже опытные разработчики периодически сталкиваются с неожиданным поведением, которое может привести к труднообнаружимым ошибкам. Рассмотрим основные подводные камни и способы их обхода. ⚠️
Ключевые ограничения и особенности чисел в JavaScript:
- Проблемы с точностью при операциях с плавающей точкой
- Ограниченный диапазон безопасных целых чисел
- Специфическое поведение NaN и Infinity
- Потеря точности при работе с очень большими или очень маленькими числами
- Особенности преобразования типов при арифметических операциях
Проблемы с плавающей точкой — самая известная особенность JavaScript. Из-за использования бинарного представления десятичных дробей возникают неожиданные результаты:
// Классические проблемы с плавающей точкой
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.3 – 0.1); // 0.19999999999999998
console.log(0.1 + 0.2 === 0.3); // false
// Решения проблемы с плавающей точкой:
// 1. Использование округления
console.log((0.1 + 0.2).toFixed(1)); // "0.3"
// 2. Использование эпсилон для сравнения
function areFloatsEqual(a, b) {
return Math.abs(a – b) < Number.EPSILON;
}
console.log(areFloatsEqual(0.1 + 0.2, 0.3)); // true
// 3. Использование целых чисел путем масштабирования
console.log((0.1 * 10 + 0.2 * 10) / 10); // 0.3
Ограничения диапазона целых чисел:
// Демонстрация пределов целых чисел
const maxSafeInt = Number.MAX_SAFE_INTEGER;
console.log(maxSafeInt); // 9007199254740991
console.log(maxSafeInt + 1); // 9007199254740992
console.log(maxSafeInt + 2); // 9007199254740992 (ошибка, должно быть 9007199254740993)
// Решение с использованием BigInt
const bigInt = BigInt(Number.MAX_SAFE_INTEGER);
console.log(bigInt); // 9007199254740991n
console.log(bigInt + 1n); // 9007199254740992n
console.log(bigInt + 2n); // 9007199254740993n (корректно)
Специфическое поведение NaN и Infinity:
// Необычное поведение NaN
console.log(NaN === NaN); // false
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("строка")); // false
console.log(isNaN("строка")); // true (глобальная функция пытается преобразовать аргумент)
// Использование Infinity
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log(Infinity > Number.MAX_VALUE); // true
console.log(Infinity – Infinity); // NaN
console.log(Infinity * 0); // NaN
Потеря точности при работе с очень маленькими значениями:
// Демонстрация потери точности
console.log(0.0000000000000001 + 0.0000000000000002); // 3e-16
console.log(0.0000000000000001 === 0.00000000000000015); // false
console.log(0.0000000000000001 === 0.0000000000000001); // true
Особенности преобразования типов при арифметических операциях:
// Неожиданные результаты из-за преобразования типов
console.log(1 + "2"); // "12" (конкатенация строк)
console.log(1 – "2"); // -1 (числовое вычитание)
console.log("2" * 3); // 6 (числовое умножение)
console.log(6 / "2"); // 3 (числовое деление)
console.log(1 + true); // 2 (true преобразуется в 1)
console.log(1 + null); // 1 (null преобразуется в 0)
console.log(1 + undefined); // NaN (undefined преобразуется в NaN)
Рекомендации по работе с ограничениями чисел в JavaScript:
- Для финансовых расчетов и высокоточных вычислений используйте библиотеки вроде decimal.js или big.js
- Применяйте BigInt для работы с целыми числами за пределами безопасного диапазона
- При сравнении чисел с плавающей точкой всегда используйте пороговое значение (эпсилон)
- Для проверки NaN используйте только Number.isNaN(), а не глобальную функцию isNaN()
- Будьте осторожны с автоматическими преобразованиями типов — используйте строгое сравнение (===) и явные преобразования
- Всегда валидируйте пользовательский ввод перед числовыми операциями
Практический пример работы с большими числами и высокой точностью:
// Пример использования библиотеки decimal.js для финансовых расчетов
// (необходимо подключить библиотеку в проект)
// Некорректный расчет процентов нативными методами
const amount = 1234.56;
const taxRate = 0.21;
const nativeTax = amount * taxRate;
console.log(nativeTax); // 259.2576
console.log(nativeTax.toFixed(2)); // "259.26"
// Если бы мы использовали библиотеку decimal.js:
/*
import { Decimal } from 'decimal.js';
const amount = new Decimal(1234.56);
const taxRate = new Decimal(0.21);
const tax = amount.times(taxRate);
console.log(tax.toString()); // "259.2576"
console.log(tax.toFixed(2)); // "259.26"
*/
JavaScript не идеален в вопросах работы с числами, но понимание его ограничений и применение соответствующих техник позволяет построить надежные, точные вычисления. Помните: числа в JavaScript — это инструмент с определенными свойствами, и как любым инструментом, им нужно уметь пользоваться. Сконцентрируйтесь на безопасной обработке крайних случаев, чёткой валидации входных данных и использовании специализированных библиотек для сложных расчётов — и вы никогда не будете бояться числовых операций в своих проектах.
Станислав Плотников
фронтенд-разработчик