Как проверить, является ли строка в JavaScript валидным числом?
Надёжный способ: комбинация isFinite() и приведения типов
Лучший и наиболее надёжный способ проверить, является ли строка валидным числом в JavaScript — это использовать функцию isFinite() вместе с явным преобразованием строки в число. Этот подход решает все проблемы, с которыми вы столкнулись: isNaN("12.3abc") работает неправильно, пустая строка считается числом, а parseFloat обрезает хвост.
Вот правильное решение:
function isValidNumber(str) {
// Обрезаем пробелы с краёв
const trimmed = str.trim();
// Проверяем, что строка не пуста после обрезки
if (trimmed === '') return false;
// Преобразуем в число и проверяем, является ли оно конечным числом
return isFinite(Number(trimmed));
}
// Тесты
console.log(isValidNumber("123")); // true
console.log(isValidNumber("-123")); // true
console.log(isValidNumber("12.3")); // true
console.log(isValidNumber("0.5")); // true
console.log(isValidNumber(" 42 ")); // true (пробелы обрезаются)
console.log(isValidNumber("12.3abc")); // false
console.log(isValidNumber("abc")); // false
console.log(isValidNumber("")); // false
console.log(isValidNumber(" ")); // false
console.log(isValidNumber("Infinity")); // false
console.log(isValidNumber("-Infinity")); // false
console.log(isValidNumber("NaN")); // false
Почему это работает?
str.trim()— удаляет пробелы в начале и конце строки. Это важно, потому что пользователи часто случайно ставят лишние пробелы.Number(trimmed)— преобразует строку в число. Если строка — валидное число, результатом будет число (например, 123). Если строка не является числом, результатом будетNaN.isFinite()— проверяет, является ли значение конечным числом. Она возвращаетfalseдля:NaN(не число)Infinityи-Infinity(бесконечность)undefined
isFinite()корректно обрабатывает строки, потому что JavaScript автоматически преобразует строку в число внутри этой функции.- Проверка на пустую строку — важна, потому что
Number("")возвращает 0, аisFinite(0)возвращаетtrue. Но пустая строка — это не число!
Альтернатива с регулярным выражением
Если вы предпочитаете более явный подход, можно использовать регулярное выражение для проверки формата числа:
function isValidNumberRegex(str) {
const trimmed = str.trim();
// Регулярное выражение для целых и дробных чисел (включая отрицательные)
return /^-?\d+(\.\d+)?$/.test(trimmed);
}
console.log(isValidNumberRegex("123")); // true
console.log(isValidNumberRegex("-123.45")); // true
console.log(isValidNumberRegex("12.3abc")); // false
Однако этот метод не обрабатывает научную нотацию (например, "1e5") и может быть менее производительным для больших объёмов данных. Поэтому первый вариант с isFinite() является более универсальным и рекомендуется к использованию в большинстве случаев.
Почему isNaN() подводит?
Функция isNaN() имеет особенность: она сначала преобразует аргумент в число. Поэтому isNaN("12.3abc") сначала пытается преобразовать строку в число, получает NaN и возвращает true — то есть "это не число". Но isNaN("") преобразует пустую строку в 0, а 0 — это число, поэтому возвращается false (строка считается числом). Это неинтуитивно и ненадёжно для валидации пользовательского ввода.
В современных проектах рекомендуется использовать Number.isNaN() (статический метод), который не выполняет принудительное преобразование типов, но для полной валидации строки его всё равно недостаточно — он не отсекает пустые строки и бесконечности.
Использование Number.parseFloat() с дополнительной проверкой
Другой подход — использовать parseFloat() вместе с проверкой, что результат преобразования совпадает с исходной строкой после обрезки:
function isValidNumberParse(str) {
const trimmed = str.trim();
if (trimmed === '') return false;
const num = parseFloat(trimmed);
// Проверяем, что результат преобразования — конечное число
// И что при обратном преобразовании в строку мы получаем то же самое
return isFinite(num) && String(num) === trimmed;
}
// Тесты
console.log(isValidNumberParse("123")); // true
console.log(isValidNumberParse("12.3")); // true
console.log(isValidNumberParse("12.3abc")); // false (parseFloat даст 12.3, но "12.3" !== "12.3abc")
console.log(isValidNumberParse(" 42 ")); // false (пробелы не сохраняются)
console.log(isValidNumberParse("00123")); // false (parseFloat вернёт 123, но "123" !== "00123")
Особенности этого подхода:
- Он строже: отклоняет строки с ведущими нулями (например, "00123") и пробелами внутри числа.
- Не поддерживает научную нотацию (например, "1e5" —
parseFloatпреобразует в 100000, но "100000" !== "1e5"). - Подходит для случаев, когда нужно строгое соответствие формату ввода.
Для большинства задач валидации пользовательского ввода (например, поля для ввода цены, возраста, количества) достаточно первого решения с isFinite(). Этот вариант стоит использовать, если важна точность формата, например, при проверке номеров документов или кодов.
Ответов пока нет.
Войдите чтобы оставить ответ