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

160

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

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

IVR Avenger
источник
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("    ")));
bendewey
источник
3
Привет, сэр, isNaN (parseInt ("123a")): вернет 123, поэтому ваше решение не будет работать, если строка содержит aplha числовой
Саджад Али Хан
6

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

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

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

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

dopeddude
источник
5

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

alert(' ' * 1); // 0
alert('x' * 1); // NaN
Greg
источник
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);
}
Bat_Programmer
источник
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 .

lucono
источник
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

JacquesB
источник
1

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

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

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

XtraSimplicity
источник
Запоздалое спасибо за это; это решило мою проблему очень хорошо.
Генри
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, вы должны сначала попытаться преобразовать его в числовое значение.

bitfishxyz
источник
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

Что о

function isNumberRegex(value) {        
    var pattern = /^[-+]?\d*\.?\d*$/i;
    var match = value.match(pattern);
    return value.length > 0 && match != null;
}
Александр Шмидт
источник
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

kiranvj
источник
0

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

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

Channox
источник