Почему isNaN («») (строка с пробелами) равно false?


160

В JavaScript почему isNaN(" ")оценивать false, но isNaN(" x")оценивать true?

Я выполнение численных операций на поле ввода текста, и я проверяю , если поле null, ""или NaN. Когда кто-то вводит в поле несколько пробелов, моя проверка не выполняется на всех трех, и я не понимаю, почему он прошел isNaNпроверку.


1
Хм ... не совсем уверен, куда ушла другая половина предмета. Предполагается читать: «JavaScript: почему isNaN (« ») имеет значение false?
IVR Avenger

Да, это поведение (пустое или пробел возвращает false для isNaN), но я не нашел точных характеристик этой функции.
Лусеро

Вот вопрос, который отвечает на это: http://stackoverflow.com/questions/115548/why-is-isnannull-false-in-js
Lucero

Javascript по этим вопросам выглядит как вуду! Вы никогда не знаете, и объяснение всегда довольно сложное. "" == false // trueиisNaN(" ") // false
Жоао Пиментел Феррейра

Ответы:


155

JavaScript интерпретирует пустую строку как 0, что затем не проходит тест isNAN. Сначала вы можете использовать parseInt для строки, которая не будет преобразовывать пустую строку в 0. Затем результат должен завершиться ошибкой isNAN.


53
Но parseInt ("123abcd") возвращает 123, что означает, что isNaN (parseInt ("123abcd")) вернет false, а должно вернуть true!
Паван Ногария

11
Так как насчет (IsNaN (строка) || isNaN (parseInt (строка)))
мат

5
Там 2 шага в переводе isNaN(arg). 1) Конвертировать arg в число, 2) Проверить, является ли это число числовым значением NaN. Это помогло мне понять это лучше.
xdhmoore

3
@Antonio_Haley Подожди, я не понимаю. Если "JavaScript интерпретирует пустую строку как 0", почему parseInt ("") возвращает NaN?
Жан-Франсуа Бошан

1
@ Жан-Франсуа. Вы правы, более правильным будет выражение «isNaN интерпретирует пустую строку как 0», а не сам JavaScript.
Антонио Хейли

82

Это может показаться удивительным, а может и нет, но вот тестовый код, который покажет вам причудливость движка JavaScript.

document.write(isNaN("")) // false
document.write(isNaN(" "))  // false
document.write(isNaN(0))  // false
document.write(isNaN(null)) // false
document.write(isNaN(false))  // false
document.write("" == false)  // true
document.write("" == 0)  // true
document.write(" " == 0)  // true
document.write(" " == false)  // true
document.write(0 == false) // true
document.write(" " == "") // false

так что это означает, что

" " == 0 == false

и

"" == 0 == false

но

"" != " "

Радоваться, веселиться :)


5
+1 Отличный пост. Можете ли вы добавить, как здесь подходит оператор тройного равенства (=== и! ==)?
Bendewey

2
Вы должны попробовать NaN === NaN или NaN == NaN ;-) Я не знаю, означает ли все это, что движок javascript дурацкий или что javascript плох для дурацких программистов.
KooiInc

10
@Kooilnc тот факт, что NaN! = NaN, на самом деле, хороший выбор на этот раз. Идея состоит в том, что NaN почти всегда является результатом вычислений, которые шли не так, как предполагал программист, и предполагать, что результаты двух вычислений, которые пошли "не так", равны, довольно опасно, я бы сказал.
скреббель

2
@Kooilnc, чтобы не отвлекать даже немного от дурацких javascript, но эти NaN просто подчиняются стандарту IEEE 754 с плавающей запятой. Вы можете читать ВСЕ об этом, как обычно, на большом W: en.wikipedia.org/wiki/NaN
Spike0xff

@NickBerardi F'ing LOL! Я так рада, что увидела этот пост. Помог мне выяснить, почему функция isNaN так запаздывает. Я уберу его из моего не полностью разработанного кода прямо сейчас и, вероятно, никогда больше не буду его использовать. Я проверить для null, ""и " "я сам. Спасибо!
VoidKing

16

Чтобы лучше это понять, откройте PDF-файл спецификации Ecma-Script на странице 43 «ToNumber, примененный к строковому типу»

если строка имеет числовой синтаксис, который может содержать любое количество символов пробела, ее можно преобразовать в тип Number. Пустая строка оценивается как 0. Также строка «Бесконечность» должна дать

isNaN('Infinity'); // false

13

Попробуйте использовать:

alert(isNaN(parseInt("   ")));

Или

alert(isNaN(parseFloat("    ")));

3
Привет, сэр, isNaN (parseInt ("123a")): вернет 123, поэтому ваше решение не будет работать, если строка содержит aplha числовой
Саджад Али Хан

6

От MDNпричины проблемы, с которой вы столкнулись

Когда аргумент функции isNaN не имеет типа Number, значение сначала приводится к Number. Полученное значение затем проверяется, чтобы определить, является ли оно NaN.

Вы можете проверить следующий исчерпывающий ответ, который также охватывает сравнение NaN на равенство.

Как проверить, является ли переменная JavaScript NaN


5

Я думаю, что это из-за типизации Javascript: ' 'конвертируется в ноль, а 'x'не:

alert(' ' * 1); // 0
alert('x' * 1); // NaN

4

Если вы хотите реализовать точную функцию isNumber, вот один из способов сделать это из Javascript: The Good Parts by Douglas Crockford [страница 105]

var isNumber = function isNumber(value) {
   return typeof value === 'number' && 
   isFinite(value);
}

4
@Xyan, в этом случае эта функция не очень полезна для выполнения задачи, которую запрашивал OP, которая заключалась в проверке строкового представления числа ...
ErikE

глупо использовать так называемый оператор строгого равенства любого заданного значения со строковым литералом, таким как «число»,
Беким Бачадж

4

Не совсем правильный ответ

Высоко проголосованный и принятый ответ Антонио Хейли делает неправильное предположение, что этот процесс проходит через функцию JavaScript parseInt:

Вы можете использовать parseInt для строки ... Результат должен потерпеть неудачу isNAN.

Мы можем легко опровергнуть это утверждение строкой "123abc":

parseInt("123abc")    // 123     (a number...
isNaN("123abc")       // true     ...which is not a number)

При этом мы можем видеть, что parseIntфункция JavaScript возвращается "123abc"как число 123, но его isNaNфункция сообщает нам, что "123abc" это не число.

Правильный ответ

ECMAScript-262 определяет, как isNaNработает проверка в разделе 18.2.3 .

18.2.3 isNaN(число)

isNaNФункция является %isNaN%внутренней задачей. Когда isNaNфункция вызывается с одним номером аргумента, предпринимаются следующие шаги:

  1. Пусть numбудет? ToNumber(number),
  2. Если numесть NaN, верните true.
  3. В противном случае вернитесь false.

В ToNumberссылках функции она определена в ECMAScript-262 в разделе 7.1.3 . Здесь нам рассказывают, как JavaScript обрабатывает строки, которые передаются этой функции.

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

A, StringNumericLiteralкоторый пуст или содержит только пробел, преобразуется в +0.

Таким образом, " "строка примера преобразуется в +0число.

В том же разделе также говорится:

Если грамматика не может быть интерпретирована Stringкак расширение StringNumericLiteral, то результатом ToNumberявляется NaN.

Без цитирования всех проверок, содержащихся в этом разделе, " x"приведенный в вопросе пример попадает в вышеуказанное условие, поскольку его нельзя интерпретировать как a StringNumericLiteral. " x"поэтому преобразуется в NaN.


2

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


4
обрезанная пустая строка также не проходит тест isNaN.
Egemenk

2

Функция isNaN("")выполняет строку на номер типа принуждения

ECMAScript 3-5 определяет следующие возвращаемые значения для оператора typeof:

  • не определено
  • объект (нуль, объекты, массивы)
  • логический
  • число
  • строка
  • функция

Лучше обернуть наш тест в функциональное тело:

function isNumber (s) {
    return typeof s == 'number'? true
           : typeof s == 'string'? (s.trim() === ''? false : !isNaN(s))
           : (typeof s).match(/object|function/)? false
           : !isNaN(s)
}

Эта функция не предназначена для проверки типа переменной , вместо этого она проверяет приведенное значение . Например, логические значения и строки приводятся к числам, поэтому, возможно, вы захотите вызвать эту функцию какisNumberCoerced()

если нет необходимости проверять типы, отличные от строки и числа , то следующий фрагмент может быть использован как часть некоторого условия:

if (!isNaN(s) && s.toString().trim()!='') // 's' can be boolean, number or string
    alert("s is a number")

1

Я предлагаю вам использовать следующую функцию, если вы действительно хотите правильно проверить, является ли она целым числом:

function isInteger(s)
{
   return Math.ceil(s) == Math.floor(s);
}

1

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

От MDN :

Начиная с самых ранних версий isNaNспецификации функции, ее поведение для нечисловых аргументов сбивает с толку. Когда аргумент isNaNфункции не имеет типа Number, значение сначала приводится к Number. Полученное значение затем проверяется, чтобы определить, так ли это NaN. Таким образом, для ненулевых чисел, которые при приведении к числовому типу приводят к допустимому числовому значению, отличному от NaN (в частности, к пустой строке и логическим примитивам, которые при приведении дают числовые значения ноль или единицу), возвращаемое значение «ложь» может быть неожиданным; например, пустая строка, безусловно, «не число».

Также обратите внимание, что в ECMAScript 6 теперь есть Number.isNaNметод, который согласно MDN:

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

К сожалению :

Даже у Number.isNaNметода ECMAScript 6 есть свои проблемы, как об этом говорится в сообщении в блоге - Исправление уродливой проблемы JavaScript и ES6 NaN .


1

isNaNФункция ожидает номер в качестве аргумента, поэтому аргументы любого другого типа (в вашем случае строки) будут преобразованы в номер , прежде чем выполняются фактическая функция логики. (Имейте NaNв виду, что это также значение типа Number!)

Btw. это является общим для всех встроенных функций - если они ожидают аргумент определенного типа, фактический аргумент будет преобразован с использованием стандартных функций преобразования. Существуют стандартные преобразования между всеми основными типами (bool, string, number, object, date, null, undefined.)

Стандартное преобразование для Stringчтобы Numberможно вызвать явно с Number(). Итак, мы можем видеть, что:

  • Number(" ") оценивает 0
  • Number(" x") оценивает NaN

Учитывая это, результат isNaNфункции полностью логичен!

Реальный вопрос заключается в том, почему стандартное преобразование строк в числа работает так, как оно работает. Преобразование строки в число действительно предназначено для преобразования числовых строк, таких как «123» или «17.5e4», в эквивалентные числа. Преобразование сначала пропускает начальные пробелы (поэтому «123» является действительным), а затем пытается проанализировать остатки как число. Если он не разбирается как число («x» - нет), то результатом будет NaN. Но есть явное специальное правило, что строка, которая является пустой или только пробелом, преобразуется в 0. Так что это объясняет преобразование.

Ссылка: http://www.ecma-international.org/ecma-262/5.1/#sec-9.3.1


1

Я написал эту быструю небольшую функцию, чтобы помочь решить эту проблему.

function isNumber(val) {
     return (val != undefined && val != null && val.toString().length > 0 && val.toString().match(/[^0-9\.\-]/g) == null);
};

Он просто проверяет наличие любых символов, которые не являются числовыми (0-9), не являются '-' или '.', И которые не являются неопределенными, нулевыми или пустыми, и возвращает true, если совпадений нет. :)


Запоздалое спасибо за это; это решило мою проблему очень хорошо.
Генри

1

Как было объяснено другим, isNaNфункция будет приводить пустую строку к числу перед проверкой, тем самым изменяя пустую строку на 0 (что является допустимым числом). Однако я обнаружил, что parseIntфункция будет возвращаться NaNпри попытке проанализировать пустую строку или строку только с пробелами. Таким образом, следующая комбинация работает хорошо:

if ( isNaN(string) || isNaN(parseInt(string)) ) console.log('Not a number!');

Эта проверка будет работать для положительных чисел, отрицательных чисел и чисел с десятичной точкой, поэтому я считаю, что она охватывает все распространенные числовые случаи.


1

NaN ! == "не число"

NaN это значение типа номера

это определение isNaN () в ECMAScript

1. Let num be ToNumber(number).
2. ReturnIfAbrupt(num).
3. If num is NaN, return true.
4. Otherwise, return false.

Попробуйте преобразовать любое значение в число.

Number(" ") // 0
Number("x") // NaN
Number(null) // 0

Если вы хотите определить, является ли это значение NaN, вы должны сначала попытаться преобразовать его в числовое значение.


0

Эта функция, казалось, работала в моих тестах

function isNumber(s) {
    if (s === "" || s === null) {
        return false;
    } else {
        var number = parseInt(s);
        if (number == 'NaN') {
            return false;
        } else {
            return true;
        }
    }
}

2
Вся ваша функция может быть написана:return !(s === "" || s === null || parseInt(s) == 'NaN');
ErikE


0

JavaScript встроенный в IsNaN функции, это - как и следовало ожидать , по умолчанию - это «Динамический тип оператора». Поэтому все значения, которые (во время процесса DTC) могут дать простую истину | ложь, например "", " ", " 000", не может быть NaN.

Это означает, что переданный аргумент сначала будет преобразован, как в:

function isNaNDemo(arg){
   var x = new Number(arg).valueOf();
   return x != x;
}

Объяснение:

В верхней строке тела функции мы (сначала) пытаемся успешно преобразовать аргумент в числовой объект. И (второй), с помощью оператора точки мы - для собственного удобства - сразу вырежешь, на примитивное значение создаваемого объекта.

Во второй строке мы берем значение, полученное на предыдущем шаге, и преимущество того факта, что NaN не равен чему-либо во вселенной, даже самому себе, например: NaN == NaN >> falseчтобы окончательно сравнить его (для неравенства) с самим собой ,

Таким образом, функция return выдаст true только тогда и только тогда, когда предоставленный аргумент return является неудачной попыткой преобразования в числовой объект, т. Е. В число, не являющееся числом; например, NaN.


isNaNstatic ()

Однако для оператора статического типа - при необходимости и при необходимости - мы можем написать гораздо более простую функцию, такую ​​как:

function isNaNstatic(x){   
   return x != x;
}

И вообще избегайте DTC, чтобы, если аргумент не был явным числом NaN, он вернул бы false. А потому тестирование на следующее:

isNaNStatic(" x"); // will return false потому что это все еще строка.

Однако: isNaNStatic(1/"x"); // will of course return true.как будет, например isNaNStatic(NaN); >> true.

Но вопреки тому isNaN, isNaNStatic("NaN"); >> falseпотому что это (аргумент) является обычной строкой.

PS: статическая версия isNaN может быть очень полезна в современных сценариях кодирования. И это вполне может быть одной из основных причин, почему я нашел время для публикации этого.

С уважением.


0

isNAN(<argument>)это функция для определения, является ли данный аргумент недопустимым числом isNaNTypecasts аргументы в числовой тип. Если вы хотите проверить, является ли аргумент числовым или нет? Пожалуйста, используйте $.isNumeric()функцию в JQuery.

Таким образом, isNaN (foo) эквивалентно isNaN (Number (foo)). Он принимает любые строки, имеющие все цифры, в качестве чисел по очевидным причинам. Например

isNaN(123) //false
isNaN(-1.23) //false
isNaN(5-2) //false
isNaN(0) //false
isNaN('123') //false
isNaN('Hello') //true
isNaN('2005/12/12') //true
isNaN('') //false
isNaN(true) //false
isNaN(undefined) //true
isNaN('NaN') //true
isNaN(NaN) //true
isNaN(0 / 0) //true

0

Я использую это

    function isNotANumeric(val) {
    	if(val.trim && val.trim() == "") {
         return true;
      } else {
      	 return isNaN(parseFloat(val * 1));
      }
    }
    
    alert(isNotANumeric("100"));  // false
    alert(isNotANumeric("1a"));   // true
    alert(isNotANumeric(""));     // true
    alert(isNotANumeric("   "));  // true


0

При проверке, если определенное строковое значение с пробелами или " ", isNaNвозможно, попытаться выполнить проверку строки, например:

// value = "123 " if (value.match(/\s/) || isNaN(value)) { // do something }

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.