ПроКодинг - Откроем для вас мир IT!

Знаете эту классическую шутку про parseInt и число 8? Или почему ваш код вдруг начал считать "010" как 8 вместо 10? Если вы когда-нибудь ловили баг из-за того, что строка превратилась не в то число, которое вы ожидали, виноват один параметр - radix (основание системы счисления). Многие разработчики игнорируют его, считая лишним. А потом тратят часы на отладку.

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

Что такое parseInt и зачем он вообще нужен

parseInt - это встроенная функция языка JavaScript, которая анализирует строку и возвращает целое число в указанной системе счисления. Звучит просто, правда? Но здесь кроется первый подвох. В отличие от оператора унарного плюса (+str) или функции Number(), parseInt умеет читать строки с мусором в конце. Например, parseInt("123abc") вернет 123, а Number("123abc") выдаст NaN (Not a Number).

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

Radix: скрытый переключатель реальности

Сигнатура метода выглядит так: parseInt(string, radix). Первый аргумент - ваша строка. Второй - основание системы счисления (от 2 до 36). По умолчанию, если вы не указали radix, браузер сам решает, какая система используется. И вот тут начинается магия.

В старых версиях JavaScript (до ES5) существовало правило: если строка начиналась с "0", интерпретатор мог решить, что это восьмеричная система (base 8). Если с "0x" - шестнадцатеричная (base 16). Для всего остального использовалась десятичная (base 10).

Поведение parseInt без явного указания radix (исторический контекст и современные стандарты)
Входная строка Старый IE (IE8 и ниже) Современные браузеры (ES5+) Ожидаемый результат
"010" 8 (восьмеричная) 10 (десятичная) Зависит от контекста
"0x10" 16 (шестнадцатеричная) 16 (шестнадцатеричная) 16
"10" 10 (десятичная) 10 (десятичная) 10

Да, сейчас большинство движков (Chrome, Firefox, Safari) всегда используют десятичную систему по умолчанию, даже для строк вида "010". Но Legacy-код и специфические окружения могут преподнести сюрпризы. Поэтому золотое правило: всегда явно указывайте radix.

Абстрактная визуализация преобразования чисел через системы счисления

Работа с двоичной и шестнадцатеричной системами

Зачем менять основание системы счисления? Представьте, что вы пишете инструмент для работы с цветовыми кодами CSS или бинарными флагами в сетевых протоколах.

Для шестнадцатеричных чисел (hex) используйте radix 16:

const hexString = "FF";
const decimalValue = parseInt(hexString, 16); // 255

Если вы забудете указать 16, parseInt("FF") вернет NaN, потому что буквы F и G не являются цифрами в десятичной системе. А вот parseInt("0xFF", 16) тоже сработает корректно, так как префикс "0x" игнорируется, когда вы явно задали основание.

С двоичной системой (binary) история похожая. Допустим, у вас есть битовая маска "1010":

const binaryString = "1010";
const value = parseInt(binaryString, 2); // 10

Без второго аргумента вы получите 1010 (тысяча десять), что совсем не то, что нужно для побитовых операций.

Частые ошибки и ловушки

Разработчики часто попадают в одни и те же ямы. Вот самые распространенные:

  • Игнорирование пустых строк. parseInt("") вернет NaN. Проверьте входные данные перед конвертацией.
  • Пробелы в начале. Функция пропускает ведущие пробелы, но не внутренние. parseInt(" 12 ") вернет 12, а parseInt("1 2") - 1.
  • Некорректный radix. Если вы передадите radix 1 или больше 36, функция вернет NaN. Основание должно быть целым числом от 2 до 36 включительно.
  • Смешивание типов. Не пытайтесь использовать parseInt для дробных чисел. parseInt("3.14") вернет 3. Дробную часть он просто отбрасывает. Используйте parseFloat или Number() для плавающей точки.
Стеклянный мост из цифр, символизирующий надежность явного radix

Альтернативы: Number() против parseInt()

Когда что использовать? Это вопрос семантики и строгости.

Сравнение методов преобразования строк в числа
Характеристика parseInt(str, radix) Number(str) +str (унарный плюс)
Поддержка систем счисления Да (через radix) Нет (только десятичная и научная) Нет
Обработка мусора в конце Да (останавливается на первом неверном символе) Нет (вернет NaN) Нет (вернет NaN)
Результат для "12.5" 12 (целое) 12.5 (число с плавающей точкой) 12.5 (число с плавающей точкой)
Результат для "" NaN 0 0

Если вам нужны строго целые числа из потенциально грязных строк - берите parseInt. Если важна чистота данных и работа с дробями - выбирайте Number(). Унарный плюс - это быстрый хак для минификации кода, но он менее читаем и ведет себя странно с пустыми строками.

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

Чтобы ваш код был надежным, следуйте этим принципам:

  1. Всегда пишите radix. Даже если вы уверены, что используете десятичную систему. Явное лучше неявного. Пишите parseInt(value, 10).
  2. Валидируйте входные данные. Перед парсингом убедитесь, что строка содержит ожидаемые символы. Регулярное выражение /^[0-9]+$/ поможет отсеять мусор для десятичных чисел.
  3. Проверяйте на NaN. Результат работы parseInt может быть NaN. Используйте Number.isNaN(result) для проверки. Обычный оператор == или === с NaN не работает корректно.
  4. Избегайте parseInt для денег. Из-за потери точности и округления вниз никогда не используйте его для финансовых расчетов. Используйте библиотеки вроде Decimal.js или храните суммы в центах как целые числа.

Помните, что в современных стандартах ECMAScript поведение стало более предсказуемым, но привычка явно указывать основание системы счисления остается лучшим примером defensive programming (защищенного программирования).

Почему parseInt("010") раньше возвращал 8?

В старых реализациях JavaScript (особенно в Internet Explorer до версии 9) ведущий ноль трактовался как признак восьмеричной системы счисления (base 8). Поэтому "010" в восьмеричной системе равно 8 в десятичной. Современные стандарты (ES5+) изменили это поведение, чтобы по умолчанию всегда использовать десятичную систему, если не указан radix, но во избежание путаницы всегда рекомендуется указывать base 10 явно.

Что вернет parseInt("12px", 10)?

Функция вернет 12. parseInt сканирует строку слева направо и останавливается на первом символе, который не является допустимой цифрой для указанной системы счисления. Буква 'p' не является цифровой в десятичной системе, поэтому парсинг прекращается, и возвращается уже накопленное значение 12.

Можно ли использовать parseInt для отрицательных чисел?

Да, можно. parseInt корректно обрабатывает знак минус в начале строки. Например, parseInt("-10", 10) вернет -10. Однако знак должен стоять непосредственно перед цифрами; пробел между знаком и числом может привести к неожиданному результату или NaN в зависимости от реализации, хотя обычно ведущие пробелы игнорируются.

Какая разница между parseInt и parseFloat?

parseInt всегда возвращает целое число, отбрасывая дробную часть. parseFloat возвращает число с плавающей запятой, сохраняя дробную часть. Например, для строки "3.14": parseInt вернет 3, а parseFloat вернет 3.14. Также parseFloat игнорирует второй аргумент (radix) и всегда работает с десятичной системой.

Как проверить, является ли результат NaN?

Не используйте сравнение result == NaN или result === NaN, так как NaN не равен самому себе. Правильный способ - использовать встроенную функцию Number.isNaN(result). Она возвращает true, только если значение действительно является значением NaN типа Number.