Perché isNaN (null) == false in JS?


129

Questo codice in JS mi dà un popup che dice "Penso che null sia un numero", che trovo leggermente inquietante. Cosa mi sto perdendo?

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

Sto usando Firefox 3. È un bug del browser?

Altri test:

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

Quindi, il problema sembra non essere un confronto esatto con NaN?

Modifica: ora la risposta alla domanda, ho ripulito il mio post per avere una versione migliore per l'archivio. Tuttavia, ciò rende alcuni commenti e persino alcune risposte un po 'incomprensibili. Non dare la colpa ai loro autori. Tra le cose che ho cambiato c'era:

  • Rimossa una nota che diceva che avevo rovinato il titolo in primo luogo ripristinandone il significato
  • Le risposte precedenti hanno mostrato che non ho indicato abbastanza chiaramente perché pensassi che il comportamento fosse strano, quindi ho aggiunto gli esempi che controllano una stringa e fanno un confronto manuale.

3
non intendi "Perché isNaN (null) == false"?
Matt Rogish,

Sulla base del tuo codice, isnan (null) restituisce false (null non è "non un numero") se dice "Penso che null sia un numero".
Devinmoore,

Risposte:


114

Credo che il codice stia cercando di chiedere "è xnumerico?" con il caso specifico qui di x = null. La funzione isNaN()può essere utilizzata per rispondere a questa domanda, ma semanticamente si riferisce specificamente al valore NaN. Da Wikipedia per NaN:

NaN ( N ot a N umber) è un valore del tipo di dati numerico che rappresenta un valore indefinito o non rappresentabile, specialmente nei calcoli in virgola mobile.

Nella maggior parte dei casi pensiamo che la risposta a "sia null numeric?" dovrebbe essere no. Tuttavia, isNaN(null) == falseè semanticamente corretto, perché nullnon lo è NaN.

Ecco la spiegazione algoritmica:

La funzione isNaN(x)tenta di convertire il parametro passato in un numero 1 (equivalente a Number(x)) e quindi verifica se il valore è NaN. Se il parametro non può essere convertito in un numero, Number(x)verrà restituito NaN2 . Pertanto, se la conversione del parametro xin un numero risulta NaN, restituisce true; in caso contrario, restituisce false.

Quindi, nel caso specifico x = null, nullviene convertito nel numero 0, (prova a valutare Number(null)e vedi che restituisce 0,) e isNaN(0)restituisce false. Una stringa di sole cifre può essere convertita in un numero e isNaN restituisce anche false. Una stringa (ad es. 'abcd') Che non può essere convertita in un numero provocherà la isNaN('abcd')restituzione di true, in particolare perché Number('abcd')restituisce NaN.

Oltre a questi casi limite apparenti ci sono le ragioni numeriche standard per restituire NaN come 0/0.

Per quanto riguarda i test apparentemente incoerenti per l'uguaglianza mostrati nella domanda, il comportamento di NaNè specificato in modo tale che ogni confronto x == NaNsia falso, indipendentemente dall'altro operando, incluso NaNse stesso 1 .


8
BTW, NaN !== NaN. Quindi, penso, non è del tutto corretto dire Number('abcd') == NaNperché Number('abcd')è NaNma non è uguale a NaN. Adoro JavaScript.
nilfalse,

Sì. Volevo dire che lo Number('abcd')è, NaNma ho implicato che è vero per l'uguaglianza, il che non è il caso. Lo modificherò.
Glenn Moss,

Mi chiedo perché sono isNaNe Numberprogettati per comportarsi in quel modo?
Timidboy,

1
La conversione di nulla 0solo (almeno in questo contesto) avviene all'interno della isNaN()funzione, che converte il suo argomento.
Glenn Moss,

3
Numero (null) == 0 ma parseInt (null) == NaN love JS
JoshBerke

31

Mi sono appena imbattuto in questo problema da solo.

Per me, il modo migliore per usare isNaN è così

isNaN(parseInt(myInt))

prendendo l'esempio di phyzome dall'alto,

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]

(Ho allineato il risultato in base all'input, spero che sia più semplice da leggere.)

Questo mi sembra migliore.


1
Non funzionerà se myInt= "123d". parseIntconverte "123d" in 123, che quindi non supera il isNaNtest.
divesh premdeep,

anzi, se vuoi cogliere anche quello scenario, suggerisco di combinare la mia risposta e quella di Glenn. che sarà simile a questo isNaN(parseInt(str,10)) || isNaN(Number()). btw - per me, dato che devo correre parseIntper usare il valore numerico della stringa, permettendo a "123d" di essere considerato un numero valido va bene. Tuttavia vedo la necessità di rilevare anche quello scenario.
guy mograbi,

8

(L'altro mio commento ha un approccio pratico. Ecco il lato teorico.)

Ho cercato lo standard ECMA 262 , che è ciò che implementa Javascript. Le loro specifiche per isNan:

Applica ToNumber al suo argomento, quindi restituisce true se il risultato è NaN e in caso contrario restituisce false.

La Sezione 9.3 specifica il comportamento di ToNumber(che non è una funzione richiamabile, ma piuttosto un componente del sistema di conversione del tipo). Per riassumere la tabella, alcuni tipi di input possono produrre un NaN. Questi sono tipo undefined, tipo number(ma solo il valore NaN), qualsiasi oggetto la cui rappresentazione primitiva è NaNe qualsiasi cosa stringche non può essere analizzata. Questo lascia undefined, NaN, new Number(NaN), e la maggior parte delle stringhe.

Qualsiasi input di questo tipo che produce NaNcome output quando viene passato ToNumberprodurrà a truequando viene alimentato isNaN. Poiché nullpuò essere convertito correttamente in un numero, non produce true.

E questo è perché.


7

Questo è davvero inquietante. Ecco una serie di valori che ho testato:

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

Valuta (nella console Firebug) a:

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

Quando chiamo x.map(isNaN)(per chiamare isNaN su ciascun valore), ottengo:

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

In conclusione, isNaNsembra piuttosto inutile! ( Modifica : tranne per il fatto che isNaN è definito solo su Numero, nel qual caso funziona perfettamente, solo con un nome fuorviante.)

Per inciso, ecco i tipi di quei valori:

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

Cosa pensi che significhi NaN? Cosa pensi sia così fuorviante su NaN o nei test per questo? Perché sei disturbato?
Bekim Bacaj,

Bene, questo è stato 8 anni fa, ma sembra che mi abbia disturbato il fatto che 1) abbia risultati incoerenti per valori che non sono di tipo Numero e 2) restituisce sempre vero per qualcosa che non è di tipo Numero. Perché una stringa non è, in realtà, una NaN. (Vedi anche la mia altra risposta, che spiega perché questo accade.)
Tratta bene le tue mod

5

Null non è NaN, così come una stringa non è NaN. isNaN () prova solo se hai davvero l'oggetto NaN.


Ma almeno una stringa viene lanciata in un oggetto NaN, poiché isNaN ("testo") restituisce true.
Hanno Fietz,

1

Non sono esattamente sicuro quando si tratta di JS ma ho visto cose simili in altre lingue ed è di solito perché la funzione sta solo controllando se null è esattamente uguale a NaN (cioè null === NaN sarebbe falso). In altre parole, non è che pensa che null sia in realtà un numero, ma è piuttosto che null non è NaN. Questo probabilmente perché entrambi sono rappresentati diversamente in JS in modo che non siano esattamente uguali, allo stesso modo di 9! == '9'.



0

Nota:

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

L'operatore == esegue la conversione del tipo, mentre === no.

Sito Web di Douglas Crockford , un Yahoo! Evangelista JavaScript, è un'ottima risorsa per cose come questa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.