Почему isNaN (null) == false в JS? - PullRequest
       45

Почему isNaN (null) == false в JS?

108 голосов
/ 22 сентября 2008

Этот код в JS дает мне всплывающее окно с надписью «я думаю, что ноль - это число», что меня немного смущает. Чего мне не хватает?

if (isNaN(null)) {
  alert("null is not a number");
} else {
  alert("i think null is a number");
}

Я использую Firefox 3. Это ошибка браузера?

Другие тесты:

null == NaN; // false
isNaN("text"); // true
NaN == "text" // false

Итак, проблема не в точном сравнении с NaN?

Редактировать: Теперь на вопрос дан ответ, я очистил свой пост, чтобы иметь лучшую версию для архива. Однако это делает некоторые комментарии и даже некоторые ответы немного непонятными. Не вините их авторов. Среди вещей, которые я изменил, было:

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

Ответы [ 8 ]

102 голосов
/ 22 сентября 2008

Я полагаю, что код пытается спросить, "является ли x числовым?" с конкретным случаем здесь x = null. Функция isNaN() может использоваться для ответа на этот вопрос, но семантически она относится конкретно к значению NaN. Из Википедии для NaN:

NaN ( N ot a N umber) - это значение числового типа данных, представляющее неопределенное или непредставляемое значение, особенно в вычислениях с плавающей запятой .

В большинстве случаев мы думаем, что ответ "является нулевым?" должно быть нет. Однако isNaN(null) == false семантически корректен, поскольку null не является NaN.

Вот алгоритмическое объяснение:

Функция isNaN(x) пытается преобразовать переданный параметр в число 1 (эквивалентно Number(x)) и затем проверяет, является ли значение NaN. Если параметр не может быть преобразован в число, Number(x) вернет NaN 2 . Следовательно, если преобразование параметра x в число приводит к NaN, возвращается значение true; в противном случае возвращается false.

Таким образом, в конкретном случае x = null, null преобразуется в число 0 (попробуйте оценить Number(null) и убедитесь, что оно возвращает 0), а isNaN(0) возвращает false. Строка, состоящая только из цифр, может быть преобразована в число, а isNaN также возвращает false. Строка (например, 'abcd'), которая не может быть преобразована в число, приведет к тому, что isNaN('abcd') вернет true, в частности потому, что Number('abcd') возвращает NaN.

В дополнение к этим очевидным граничным случаям имеются стандартные численные причины для возврата NaN, такие как 0 / 0.

Что касается, казалось бы, противоречивых тестов на равенство, показанных в вопросе, поведение NaN задается таким образом, что любое сравнение x == NaN является ложным, независимо от другого операнда, включая сам NaN 1 .

20 голосов
/ 17 декабря 2013

Я сам столкнулся с этой проблемой.

Для меня лучший способ использовать isNaN - вот так

isNaN(parseInt(myInt))

взяв пример фитомера сверху,

var x = [undefined, NaN,     'blah', 0/0,  null, 0,     '0',   1,     1/0, -1/0,  Number(5)]
x.map( function(n){ return isNaN(parseInt(n))})
        [true,      true,    true,   true, true, false, false, false, true, true, false]

(Я выровнял результат в соответствии с входными данными, надеюсь, это облегчит чтение.)

Мне кажется, это лучше.

7 голосов
/ 23 сентября 2008

(Мой другой комментарий требует практического подхода. Вот теоретическая сторона.)

Я посмотрел стандарт ECMA 262 , который реализует Javascript. Их спецификация для isNan:

Применяет ToNumber к своему аргументу, затем возвращает true, если результат равен NaN, и в противном случае возвращает false.

Раздел 9.3 определяет поведение ToNumber (которое не является вызываемой функцией, а скорее компонентом системы преобразования типов). Подводя итог таблицы, некоторые типы ввода могут создавать NaN. Это тип undefined, тип number (но только значение NaN), любой объект с примитивным представлением NaN и любой string, который не может быть проанализирован. Это оставляет undefined, NaN, new Number(NaN) и большинство строк.

Любой такой вход, который выдает NaN в качестве выхода при передаче на ToNumber, будет выдавать true при подаче на isNaN. Поскольку null может быть успешно преобразовано в число, оно не выдает true.

И вот почему.

7 голосов
/ 23 сентября 2008

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

var x = [undefined, NaN, 'blah', 0/0, null, 0, '0', 1, 1/0, -1/0, Number(5)]

Оценивает (в консоли Firebug):

,NaN,blah,NaN,,0,0,1,Infinity,-Infinity,5

Когда я звоню x.map(isNaN) (чтобы вызвать isNaN для каждого значения), я получаю:

true,true,true,true,false,false,false,false,false,false,false

В заключение, isNaN выглядит довольно бесполезно! ( Редактировать : за исключением того, что оказывается, что isNaN является только определенным над номером, в этом случае он работает просто отлично - только с вводящим в заблуждение именем.)

Кстати, вот типы этих значений:

x.map(function(n){return typeof n})
-> undefined,number,string,number,object,number,string,number,number,number,number
5 голосов
/ 22 сентября 2008

Ноль не является NaN, так же как строка не является NaN. isNaN () просто проверьте, действительно ли у вас есть объект NaN.

1 голос
/ 23 апреля 2015

В ES5 он определен как isNaN (number) и возвращает true, если аргумент приводит к NaN, а в противном случае возвращает false.

  • Если ToNumber (число) равно NaN, вернуть true.
  • В противном случае вернуть false.

И посмотрите Абстрактную операцию преобразования таблицы ToNumber . Так что внутренне JS двигатель оценивает ToNumber(Null) это +0, тогда в итоге isNaN(null) будет false

1 голос
/ 22 сентября 2008

Я не совсем уверен, когда дело доходит до JS, но я видел подобные вещи на других языках, и обычно это происходит потому, что функция проверяет, является ли значение null точно равным NaN (т. Е. Null === NaN будет ложным ). Другими словами, дело не в том, что он думает, что на самом деле ноль - это число, а в том, что ноль - это не NaN. Вероятно, это связано с тем, что оба представлены в JS по-разному, поэтому они не будут в точности равны, так же, как 9! == '9'.

0 голосов
/ 23 сентября 2008

Примечание:

"1" == 1 // true
"1" === 1 // false

Оператор == выполняет преобразование типов, а === - нет.

Сайт Дугласа Крокфорда , Yahoo! Евангелист JavaScript - отличный ресурс для подобных вещей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...