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

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

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

Ответ 1

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

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

В большинстве случаев мы думаем, что ответ на "нулевой числовой?" не должно быть. Однако 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.

Ответ 2

Я сам столкнулся с этим вопросом.

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

isNaN(parseInt(myInt))

взяв пример phyzome сверху,

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]

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

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

Ответ 3

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

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

Ответ 4

(Мой другой комментарий использует практический подход. Здесь теоретическая сторона.)

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

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

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

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

И вот почему.

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

И см. Таблица преобразования toNumber абстрактной операции. Таким образом, внутренне js engine оценивает ToNumber(Null) is +0, а затем isNaN(null) есть false

Ответ 8

Примечание:

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

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

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