it-swarm.com.de

Warum ist isNaN (null) == in JS falsch?

Dieser Code in JS gibt mir ein Popup mit der Aufschrift "Ich denke null ist eine Zahl", was mich etwas beunruhigt. Was vermisse ich?

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

Ich verwende Firefox 3. Ist das ein Browser-Fehler?

Andere Tests:

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

Das Problem scheint also kein genauer Vergleich mit NaN zu sein?

Bearbeiten: Nachdem die Frage beantwortet wurde, habe ich meinen Beitrag aufgeräumt, um eine bessere Version für das Archiv zu haben. Dies macht jedoch einige Kommentare und sogar einige Antworten ein wenig unverständlich. Beschuldigen Sie nicht ihre Autoren. Unter den Dingen, die ich geändert habe, war:

  • Es wurde eine Notiz entfernt, die besagt, dass ich die Überschrift in erster Linie durch Umkehrung ihrer Bedeutung durcheinander gebracht hatte
  • Frühere Antworten zeigten, dass ich nicht klar genug darlegte, warum ich das Verhalten für verrückt hielt. Deshalb fügte ich die Beispiele hinzu, die eine Zeichenfolge überprüfen und einen manuellen Vergleich durchführen.
114
Hanno Fietz

Ich glaube, der Code versucht zu fragen: "Ist x numerisch?" mit dem speziellen Fall hier von x = null. Die Funktion isNaN() kann verwendet werden, um diese Frage zu beantworten, bezieht sich jedoch semantisch speziell auf den Wert NaN. Aus Wikipedia für NaN :

NaN (Not einNumber) ist ein Wert des numerischen Datentyps, der einen undefinierten oder nicht darstellbaren Wert darstellt, insbesondere bei Gleitkommaberechnungen.

In den meisten Fällen denken wir, die Antwort auf "ist null numerisch?" sollte nein sein. isNaN(null) == false ist jedoch semantisch korrekt, da null nicht NaN ist.

Hier ist die algorithmische Erklärung:

Die Funktion isNaN(x) versucht, den übergebenen Parameter in eine Zahl umzuwandeln1 (entspricht Number(x)) und prüft dann, ob der Wert NaN ist. Wenn der Parameter nicht in eine Zahl konvertiert werden kann, gibt Number(x)NaN zurück.2. Wenn die Konvertierung des Parameters x in eine Zahl zu NaN führt, wird true zurückgegeben. Andernfalls wird false zurückgegeben.

In dem speziellen Fall wird x = null, null in die Zahl 0 konvertiert (versuchen Sie, Number(null) auszuwerten, und stellen Sie sicher, dass 0 zurückgegeben wird), und isNaN(0) gibt false zurück. Eine Zeichenfolge, die nur aus Ziffern besteht, kann in eine Zahl konvertiert werden, und isNaN gibt auch false zurück. Eine Zeichenfolge (z. B. 'abcd'), die nicht in eine Zahl konvertiert werden kann, bewirkt, dass isNaN('abcd') true zurückgibt, insbesondere, weil Number('abcd')NaN zurückgibt.

Zusätzlich zu diesen offensichtlichen Edge-Fällen sind dies die standardmäßigen numerischen Gründe für die Rückgabe von NaN wie 0/0.

Was die in der Frage gezeigten scheinbar inkonsistenten Tests auf Gleichheit betrifft, wird das Verhalten von NaN so spezifiziert, dass jeder Vergleich x == NaN ungeachtet des anderen Operanden, einschließlich NaN selbst, falsch ist1.

106
Glenn Moss

Ich bin gerade auf dieses Problem gestoßen.

Für mich ist die beste Art, isNaN zu verwenden, die gleiche

isNaN(parseInt(myInt))

am Beispiel von Phyzome von oben,

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]

(Ich habe das Ergebnis entsprechend der Eingabe ausgerichtet, hoffe, es erleichtert das Lesen.)

Das scheint mir besser zu sein.

21
guy mograbi

Das ist in der Tat störend. Hier ist eine Reihe von Werten, die ich getestet habe:

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

Es wertet (in der Firebug-Konsole) Folgendes aus:

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

Wenn ich x.map(isNaN) aufrufe (um isNaN für jeden Wert aufzurufen), erhalte ich:

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

Zusammenfassend sieht isNaN ziemlich nutzlos aus! (Edit: Außer es stellt sich heraus, dass isNaN nur über Number definiert ist . In diesem Fall funktioniert es einwandfrei - nur mit ein irreführender Name.)

Im Übrigen sind hier die Typen dieser Werte:

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

(Mein anderer Kommentar hat einen praktischen Ansatz. Hier ist die theoretische Seite.)

Ich habe den ECMA 262 Standard nachgeschlagen, den Javascript implementiert. Ihre Spezifikation für isNan:

Wendet ToNumber auf sein Argument an, gibt dann true zurück, wenn das Ergebnis NaN ist, und gibt andernfalls false zurück.

Abschnitt 9.3 spezifiziert das Verhalten von ToNumber (das keine aufrufbare Funktion ist, sondern eine Komponente des Typkonvertierungssystems). Um die Tabelle zusammenzufassen, können bestimmte Eingabetypen eine NaN erzeugen. Dies sind Typ undefined, Typ number (aber nur der Wert NaN), jedes Objekt, dessen primitive Darstellung NaN ist, und jedes string das kann nicht analysiert werden. Dies lässt undefined, NaN, new Number(NaN) und die meisten Zeichenfolgen übrig.

Jede solche Eingabe, die NaN als Ausgabe erzeugt, wenn sie an ToNumber übergeben wird, erzeugt true, wenn sie an isNaN weitergeleitet wird. Da null erfolgreich in eine Zahl konvertiert werden kann, wird true nicht erzeugt.

Und deshalb.

7
phyzome

Null ist nicht NaN, ebenso wie ein String nicht NaN ist. isNaN () teste einfach, ob du das NaN-Objekt wirklich hast.

5
gizmo

Ich bin nicht ganz sicher, ob es sich um JS handelt, aber ich habe ähnliche Dinge in anderen Sprachen gesehen, und das liegt normalerweise daran, dass die Funktion nur überprüft, ob null genau gleich NaN ist (d. H. Null === NaN wäre falsch). Mit anderen Worten, es ist nicht so, dass es denkt, dass Null tatsächlich eine Zahl ist, sondern dass Null nicht NaN ist. Dies liegt wahrscheinlich daran, dass beide in JS unterschiedlich dargestellt werden, sodass sie nicht genau gleich sind, wie 9! == '9'.

1
Jason Tennier

In ES5 ist es als isNaN (number) definiert und gibt true zurück, wenn das Argument auf NaN erzwungen wird, und andernfalls false zurück.

  • Wenn ToNumber (number) NaN ist, wird true zurückgegeben.
  • Andernfalls geben Sie false zurück.

Und siehe die Die abstrakte Operation ToNumber-Konvertierungstabelle . So ist es intern js Engine bewerten ToNumber(Null) ist +0, Dann schließlich isNaN(null) ist false

1
rab

Hinweis:

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

Der Operator == führt eine Typkonvertierung durch, der Operator === dagegen nicht.

Douglas Crockfords Website , ein Yahoo! JavaScript-Evangelist, ist eine großartige Ressource für solche Dinge.

0
cllpse