Чому isNaN (null) == false в JS?


129

Цей код в JS дає мені спливаюче вікно, яке говорить "я думаю, що нуль є числом", що я вважаю трохи тривожним. Що я пропускаю?

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

Я використовую Firefox 3. Це помилка браузера?

Інші тести:

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

Отже, проблема здається не точним порівнянням з NaN?

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

  • Вилучив замітку, в якій говорилося, що я перекрутив заголовок, насамперед повернувши його значення
  • Раніші відповіді показали, що я не зазначив досить чітко, чому я вважаю, що поведінка дивна, тому я додав приклади, які перевіряють рядок і роблять порівняння вручну.

3
ви не маєте на увазі "Чому isNaN (null) == false"?
Метт Рогіш

Виходячи з вашого коду, isnan (null) повертає false (null не є "не числом"), якщо він говорить "Я думаю, що null - це число".
devinmoore

Відповіді:


114

Я вважаю, що код намагається запитати, " 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)повернеться NaN2 . Отже, якщо перетворення параметра xв число призводить до NaN, воно повертає істину; в іншому випадку воно повертається помилковим.

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

На додаток до цих очевидних крайових випадків є стандартними числовими причинами повернення NaN, як 0/0.

Що стосується, здавалося б, непослідовних тестів на рівність, показаних у питанні, поведінка NaNзадається таким чином, що будь-яке порівняння x == NaNє помилковим, незалежно від іншого операнда, включаючи NaNсамого себе 1 .


8
ДО РЕЧІ NaN !== NaN. Отже, я думаю, сказати не зовсім правильно, Number('abcd') == NaNтому що Number('abcd')це, NaNале не дорівнює NaN. Я обожнюю JavaScript.
nilfalse

Так. Я мав намір донести Number('abcd')це, NaNале мав на увазі, що це перевіряє істинність на рівність, а це не так. Я його відредагую.
Гленн Мосс

Цікаво, чому вони isNaNі Numberпокликані так поводитися?
timidboy

1
Перетворення nullв 0лише (принаймні в цьому контексті) відбувається в межах isNaN()функції, яка примушує його аргумент.
Гленн Мосс

3
Кількість (null) == 0, але parseInt (null) == NaN love JS
JoshBerke

31

Я просто натрапив на це питання сам.

Для мене найкращим способом використання 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]

(Я вирівняв результат відповідно до інформації, сподіваюся, що це полегшує читання.)

Це мені здається краще.


1
Не працює, якщо myInt= "123d". parseIntперетворює "123d" в 123, що потім не відповідає isNaNтесту.
divesh premdeep

Дійсно, якщо ви також хочете спіймати цей сценарій, я пропоную поєднати мою відповідь та відповідь Глена. що буде виглядати так isNaN(parseInt(str,10)) || isNaN(Number()). btw - для мене, оскільки мені доводиться бігати parseInt, щоб використовувати числове значення рядка, що дозволяє «123d» вважати дійсним числом, це добре. Однак я бачу необхідність виявити і цей сценарій.
хлопець mograbi

8

(Інший мій коментар застосовує практичний підхід. Ось теоретична сторона.)

Я переглянув стандарт ECMA 262 , який реалізує Javascript. Їх специфікація для isNan:

Застосовує ToNumber до свого аргументу, потім повертає true, якщо результат NaN, а в іншому випадку повертає false.

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

Будь-який такий вхід, який видає NaNяк вихід при передачі на стан, ToNumberвидасть a, trueколи його подають isNaN. Оскільки його nullможна успішно перетворити на число, воно не виробляє true.

І саме тому.


7

Це справді тривожно. Ось масив значень, який я перевірив:

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)(для виклику єNaN на кожне значення), я отримую:

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

На закінчення isNaNвиглядає досить марно! ( Edit : За винятком виявляється IsNaN тільки визначається через номер, в цьому випадку вона працює просто відмінно - просто з вводить в оману назвою.)

До речі, ось типи цих значень:

x.map(function(n){return typeof n})
-> undefined,number,string,number,object,number,string,number,number,number,number

Що ви уявляєте, що має означати NaN? Як ви вважаєте, наскільки це вводить в оману NaN чи тестування на нього? Чому вас турбує?
Бекім Бачай

Що ж, це було 8 років тому, але, схоже, мене турбувало те, що 1) він має непослідовні результати для значень, що не належать до типу Number, і 2) він коли-небудь повертає істину для чогось, що не має типу Number. Тому що струна насправді не є NaN. (Також дивіться мою іншу відповідь, яка пояснює, чому це трапляється.)
добре

5

Null не NaN, а також рядок не NaN. isNaN () просто перевірити, чи дійсно є об’єкт NaN.


Але тоді принаймні рядок закидається в об’єкт NaN, як isNaN ("текст") повертає істину.
Hanno Fietz

1

Я не точно впевнений, що стосується JS, але я бачив подібні речі на інших мовах, і це зазвичай тому, що функція лише перевіряє, чи точно null дорівнює NaN (тобто null === NaN було б помилковим). Іншими словами, це не те, що він вважає, що нуль насправді є числом, а скоріше, що нуль не є NaN. Це, мабуть, тому, що обидва представлені в JS по-різному, так що вони не будуть абсолютно рівними, так само, як 9! == '9'.


1

У ES5 він визначається як isNaN (number)повертає true, якщо аргумент примушує до NaN, а в іншому випадку повертає false.

  • Якщо ToNumber (число) - NaN, поверніть true.
  • В іншому випадку поверніть помилкове.

І дивіться таблицю перетворення абстрактної операції ToNumber . Так що всередині JS двигун оцінювати ToNumber(Null)це +0, то в кінцевому підсумку isNaN(null)єfalse


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.