JavaScript - функция isNaN( ) иногда "противоречит" значению NaN

Рейтинг: 2Ответов: 4Опубликовано: 28.07.2025

Всем привет, в одной статье про преобразования типов в JavaScript я прочитал такую информацию:

"Для преобразования строки в целое число применяется функция parseInt( ).

Строка может иметь смешанное содержимое, например "123hello", то есть в данном случае есть цифры, но есть и обычные символы. Функция parseInt( ) все равно попытается выполнить преобразование - она последовательно, начиная с первого символа, считывает цифры, пока не встретит первый нецифровой символ.

Если функции parseInt( ) не удастся выполнить преобразование, то она возвращает значение NaN ("Not a Number", "не число"), которое говорит о том, что строка не представляет число и не может быть преобразована. Что интересно, само значение NaN представляет тип number.

С помощью специальной функции isNaN( ) можно проверить, представляет ли строка число. Если строка не является числом, то функция возвращает true, если это число - то false."

Рассмотрим примеры:

    // Пример 1
    const number1 = "56";
    const result1 = parseInt(number1);
    console.log(result1);              // 56
    console.log(typeof result1);       // number
    console.log(isNaN(number1));       // false

    // Пример 2
    const number2 = "123hello";
    const result2 = parseInt(number2);
    console.log(result2);              // 123
    console.log(typeof result2);       // number
    console.log(isNaN(number2));       // true

    // Пример 3
    const number3 = "hello";
    const result3 = parseInt(number3);
    console.log(result3);              // NaN
    console.log(typeof result3);       // number
    console.log(isNaN(number3));       // true

Мне здесь не понятен Пример 2, а именно строчка:

    console.log(isNaN(number2));       // true

я почему-то ожидал тут увидеть значение false. Я рассуждаю так: если isNaN(number2) это true, т.е. данная строка не является числом, то логично, что parseInt(number2) должно возвращать значение NaN ("не число"). Но раз уж разработчики языка сделали так, что "функция последовательно считывает цифры, пока не встретит первый нецифровой символ", то может тогда логичнее было бы isNaN(number2) возвращать как false?

Или может быть я зря ожидаю некой взаимосвязи между функцией isNaN( ) и значением NaN. Подскажите, где я мыслю неверно?

Ответы

▲ 1Принят

С помощью специальной функции isNaN( ) можно проверить, представляет ли строка число. Если строка не является числом, то функция возвращает true, если это число - то false."

Даже в твоей цитате есть фраза "представляет ли строка число". Т.е. именно вся строка, а не какая-то ее начальная часть может быть преобразована в число.

Улавливаешь разницу?

▲ 2

Проблема заключается в том, что функция parseInt преобразовывает переданный ей аргумент не так как функция isNaN.

Именно поэтому результаты их не совпадают.

В вопросе для 123hello

  • parseInt вернет 123
  • isNaN - сразу вернет true, так как переданная строка не конвертируется в число

функция isNaN использует для преобразования те же правила, что и функция Number (за исключением работы с BigInt)

Подробнее про то, какие правила используются при преобразовании строки в число можно посмотреть в вопросе: Разница ParseInt, ParseFloat и Number

▲ 2

Подскажите, где я мыслю неверно?

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

parseInt не подходит

Для преобразования строки в целое число применяется функция parseInt().

Не возражаю, можно. Но есть тонкие моменты. Читайте дальше.

Строка может иметь смешанное содержимое, например "123hello", то есть в данном случае есть цифры, но есть и обычные символы. Функция parseInt( ) все равно попытается выполнить преобразование - она последовательно, начиная с первого символа, считывает цифры, пока не встретит первый нецифровой символ.

Я бы ещё добавил (подробности в документации по parseInt) что:

  • первый аргумент обязательно должен быть строкой, иначе может быть странное (parseInt(0.000000001)1);
  • обязательно укажите второй аргумент – основание системы счисления, иначе может быть странное (parseInt(0x10)16);
  • пробельные символы в начале строки игнорируются;
  • из начала строки извлекается необязательный знак +/-.

Если функции parseInt() не удастся выполнить преобразование, то она возвращает значение NaN ("Not a Number", "не число"), которое говорит о том, что строка не представляет число и не может быть преобразована. Что интересно, само значение NaN представляет тип number.

Not a Number – обратите внимание на артикль a:

  • Number означает число вообще, как понятие.
  • a Number означает конкретное число с конкретным значением.
  • Not a Number означает число величина которого неизвестна. Тип у него числовой, а значение неизвестно, "что интересно".

Из этого не краткого описания ясно, что parseInt имеет массу особенностей. И если какая-то из этих особенностей вам не подходит, то и вся функция не подходит тоже.

isNaN не подходит

С помощью специальной функции isNaN() можно проверить, представляет ли строка число. Если строка не является числом, то функция возвращает true, если это число - то false.

Речь про число, слово "целое" пропало. Из документации по isNaN:

  • isNaN можно применять к строкам. В этом случае аргумент приводится к числу вызовом очень похожим на вызов Number();
  • Number предназначен для обработки любых чисел, не только целых (isNaN('.1e-1')false);
  • Number обрабатывает бесконечности (isNaN('Infinity')false).

То есть, isNaN(строка) не подходит для проверки целых чисел. И для чисел вообще её тоже надо его использовать аккуратно.

А делать-то что?

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

const readInt = s => {
    if (/^[-+]?(0|[1-9][0-9]*)$/.test(s)) {
        return parseInt(s, 10);
    }
    return Number.NaN;
};
▲ 1

isNaN() ожидает любой тип, однако, движок выполняет приведение типа аргумента для проверки наличия ошибки (как не странно, чтобы найти ошибку, ее нужно совершить), и "123hello" буквально является NaN, в отличии от "56" - все правильно лог выводит. Тут дело не в понимании функции, а в понимании процессов интерпретатора.