Warum ist isNaN ("") (Zeichenfolge mit Leerzeichen) gleich false?

160

Warum wird in JavaScript isNaN(" ")ausgewertet false, aber isNaN(" x")ausgewertet true?

Ich fahre numerische Operationen auf einem Texteingabefeld, und ich überprüfen , ob das Feld ist null, ""oder NaN. Wenn jemand eine Handvoll Leerzeichen in das Feld eingibt, schlägt meine Validierung bei allen drei fehl, und ich bin verwirrt, warum die isNaNPrüfung nicht bestanden wird.

IVR Avenger
quelle
1
Hm ... nicht ganz sicher, wohin die andere Hälfte des Themas ging. Es soll lauten: "JavaScript: Warum wird isNaN (" ") als falsch ausgewertet?"
IVR Avenger
Jes, das ist das Verhalten (leer oder Leerzeichen gibt für isNaN false zurück), aber ich habe die genauen Spezifikationen dieser Funktion nicht gefunden.
Lucero
Hier ist eine Frage, die dies beantwortet: http://stackoverflow.com/questions/115548/why-is-isnannull-false-in-js
Lucero
Javascript zu diesen Themen scheint wie Voodoo! Man weiß es nie und die Erklärung ist immer ziemlich komplex. "" == false // trueundisNaN(" ") // false
João Pimentel Ferreira

Antworten:

155

JavaScript interpretiert eine leere Zeichenfolge als 0, wodurch der isNAN-Test nicht bestanden wird. Sie können zuerst parseInt für die Zeichenfolge verwenden, wodurch die leere Zeichenfolge nicht in 0 konvertiert wird. Das Ergebnis sollte dann fehlschlagen, isNAN.

Antonio Haley
quelle
53
Aber parseInt ("123abcd") gibt 123 zurück, was bedeutet, dass isNaN (parseInt ("123abcd")) false zurückgibt, während es true zurückgeben sollte!
Pawan Nogariya
11
Wie wäre es also mit (IsNaN (Zeichenfolge) || isNaN (parseInt (Zeichenfolge)))
matt
5
Das Dolmetschen besteht aus 2 Schritten isNaN(arg). 1) Konvertiere arg in Zahl, 2) Überprüfe, ob diese Zahl der numerische Wert ist NaN. Das hat mir geholfen, es besser zu verstehen.
xdhmoore
3
@Antonio_Haley Moment mal, ich verstehe es nicht. Wenn "JavaScript eine leere Zeichenfolge als 0 interpretiert", warum gibt parseInt ("") NaN zurück?
Jean-François Beauchamp
1
@ Jean-François Sie haben Recht, die korrektere Aussage wäre "isNaN interpretiert eine leere Zeichenfolge als 0", nicht JavaScript selbst.
Antonio Haley
82

Sie werden das vielleicht überraschen oder auch nicht, aber hier ist ein Testcode, der Ihnen die Verrücktheit der JavaScript-Engine zeigt.

document.write(isNaN("")) // false
document.write(isNaN(" "))  // false
document.write(isNaN(0))  // false
document.write(isNaN(null)) // false
document.write(isNaN(false))  // false
document.write("" == false)  // true
document.write("" == 0)  // true
document.write(" " == 0)  // true
document.write(" " == false)  // true
document.write(0 == false) // true
document.write(" " == "") // false

das bedeutet also, dass

" " == 0 == false

und

"" == 0 == false

aber

"" != " "

Habe Spaß :)

Nick Berardi
quelle
5
+1 Großartiger Beitrag. Können Sie hinzufügen, wie der Operator Triple Equals (=== und! ==) hierher passt?
Bendewey
2
Sie sollten NaN === NaN oder NaN == NaN ausprobieren ;-) Ich weiß nicht, ob dies alles bedeutet, dass die Javascript-Engine verrückt ist oder dass Javascript für verrückte Programmierer schlecht ist.
KooiInc
10
@Kooilnc die Tatsache, dass NaN! = NaN eigentlich einmal eine gute Wahl ist. Die Idee ist, dass NaN fast immer das Ergebnis einer Berechnung ist, die anders verlief als vom Programmierer beabsichtigt, und anzunehmen, dass die Ergebnisse von zwei Berechnungen, die "falsch" liefen, gleich sind, ist ziemlich gefährlich, würde ich sagen.
Skrebbel
2
@Kooilnc, um die Verrücktheit von Javascript nicht einmal ein wenig zu beseitigen, aber diese NaNs halten sich nur an den Gleitkomma-Standard IEEE 754. Sie können ALLES wie gewohnt auf dem großen W lesen: en.wikipedia.org/wiki/NaN
Spike0xff
@ NickBerardi F'ing LOL! Ich bin so froh, diesen Beitrag gesehen zu haben. Hat mir geholfen herauszufinden, warum die isNaN-Funktion so verzögert ist. Ich werde es jetzt aus meinem nicht vollständig entwickelten Code entfernen und es wahrscheinlich nie wieder verwenden. Ich werde überprüfen , für null, ""und " "mich selbst. Vielen Dank!
VoidKing
16

Um es besser zu verstehen, öffnen Sie bitte das Ecma-Script-Spezifikations-PDF auf Seite 43 "ToNumber Applied to the String Type".

Wenn eine Zeichenfolge eine numerische Syntax hat, die eine beliebige Anzahl von Leerzeichen enthalten kann, kann sie in den Typ Zahl konvertiert werden. Leere Zeichenfolge wird mit 0 ausgewertet. Auch die Zeichenfolge 'Unendlichkeit' sollte geben

isNaN('Infinity'); // false
Rafael
quelle
13

Versuchen Sie es mit:

alert(isNaN(parseInt("   ")));

Oder

alert(isNaN(parseFloat("    ")));
Bendewey
quelle
3
Hallo Sir, isNaN (parseInt ("123a")): Gibt 123 zurück, sodass Ihre Lösung nicht funktioniert, wenn die Zeichenfolge eine aplha-Zahl enthält
Sajjad Ali Khan
6

Aus dem MDNGrund für das Problem, mit dem Sie konfrontiert sind

Wenn das Argument für die Funktion isNaN nicht vom Typ Number ist, wird der Wert zuerst zu einer Number gezwungen. Der resultierende Wert wird dann getestet, um festzustellen, ob es sich um NaN handelt.

Möglicherweise möchten Sie die folgende umfassende Antwort überprüfen, die auch den NaN-Vergleich auf Gleichheit abdeckt.

So testen Sie, ob eine JavaScript-Variable vorhanden ist NaN

Dopeddude
quelle
5

Ich denke, es liegt an der Eingabe von Javascript: ' 'wird in Null konvertiert, wohingegen 'x'nicht:

alert(' ' * 1); // 0
alert('x' * 1); // NaN
Greg
quelle
4

Wenn Sie eine genaue isNumber-Funktion implementieren möchten, finden Sie hier eine Möglichkeit, dies mit Javascript zu tun : The Good Parts von Douglas Crockford [Seite 105]

var isNumber = function isNumber(value) {
   return typeof value === 'number' && 
   isFinite(value);
}
Brian Grinstead
quelle
4
@ Xyan In diesem Fall ist diese Funktion nicht sehr hilfreich, um die vom OP angeforderte Aufgabe auszuführen, nämlich die
Überprüfung
Es ist dumm, den sogenannten strengen Gleichheitsoperator eines bestimmten Wertes gegen ein Zeichenfolgenliteral wie "Zahl" zu verwenden.
Bekim Bacaj
4

Die nicht ganz richtige Antwort

Antonio Haleys hoch gelobte und akzeptierte Antwort hier geht falsch davon aus, dass dieser Prozess die parseIntFunktion von JavaScript durchläuft :

Sie können parseInt für die Zeichenfolge verwenden ... Das Ergebnis sollte dann fehlschlagen, isNAN.

Wir können diese Aussage leicht mit der Zeichenfolge widerlegen "123abc":

parseInt("123abc")    // 123     (a number...
isNaN("123abc")       // true     ...which is not a number)

Damit können wir sehen, dass die JavaScript- parseIntFunktion "123abc"als Zahl zurückgegeben wird 123, aber die isNaNFunktion sagt uns, dass dies "123abc" keine Zahl ist.

Die richtige Antwort

ECMAScript-262 definiert isNaNin Abschnitt 18.2.3, wie die Prüfung funktioniert .

18.2.3 isNaN(Nummer)

Die isNaNFunktion ist das %isNaN%intrinsische Objekt. Wenn die isNaNFunktion mit einer Argumentnummer aufgerufen wird, werden die folgenden Schritte ausgeführt:

  1. Lass numsein? ToNumber(number).
  2. Wenn numja NaN, kehren Sie zurück true.
  3. Andernfalls kehren Sie zurück false.

Die ToNumberFunktion, auf die verwiesen wird, ist auch in Abschnitt 7.1.3 von ECMAScript-262 definiert . Hier erfahren wir, wie JavaScript mit Strings umgeht, die an diese Funktion übergeben werden.

Das erste Beispiel in der Frage ist eine Zeichenfolge, die nur Leerzeichen enthält. In diesem Abschnitt heißt es:

A StringNumericLiteral, das leer ist oder nur Leerzeichen enthält, wird in konvertiert +0.

Die " "Beispielzeichenfolge wird daher in +0eine Zahl konvertiert .

Im selben Abschnitt heißt es auch:

Wenn die Grammatik die nicht interpretieren kann Stringals Erweiterung StringNumericLiteral, dann das Ergebnis ToNumberheißt NaN.

Ohne alle in diesem Abschnitt enthaltenen Prüfungen zu zitieren, " x"fällt das in der Frage angegebene Beispiel in die obige Bedingung, da es nicht als a interpretiert werden kann StringNumericLiteral. " x"wird daher in konvertiert NaN.

James Donnelly
quelle
2

Ich bin mir nicht sicher warum , aber um das Problem zu umgehen, können Sie vor dem Überprüfen immer Leerzeichen kürzen. Sie möchten das wahrscheinlich trotzdem tun.

Joel Coehoorn
quelle
4
Eine zugeschnittene leere Zeichenfolge schlägt ebenfalls fehl. isNaN-Test.
Egemenk
2

Die Funktion isNaN("")führt einen Zwang vom Typ String zu Number aus

ECMAScript 3-5 definiert die folgenden Rückgabewerte für den Operatortyp:

  • nicht definiert
  • Objekt (null, Objekte, Arrays)
  • Boolescher Wert
  • Nummer
  • Zeichenfolge
  • Funktion

Wickeln Sie unseren Test besser in einen Funktionskörper:

function isNumber (s) {
    return typeof s == 'number'? true
           : typeof s == 'string'? (s.trim() === ''? false : !isNaN(s))
           : (typeof s).match(/object|function/)? false
           : !isNaN(s)
}

Diese Funktion ist nicht auf Testvariablen intented Typ , stattdessen testet er den erzwungener Wert . Zum Beispiel werden Boolesche Werte und Zeichenfolgen zu Zahlen gezwungen. Vielleicht möchten Sie diese Funktion als aufrufenisNumberCoerced()

Wenn Sie nicht nach anderen Typen als Zeichenfolge und Nummer testen müssen, wird möglicherweise das folgende Snippet als Teil einer Bedingung verwendet:

if (!isNaN(s) && s.toString().trim()!='') // 's' can be boolean, number or string
    alert("s is a number")
Steven Pribilinskiy
quelle
1

Ich empfehle Ihnen, die folgende Funktion zu verwenden, wenn Sie wirklich überprüfen möchten, ob es sich um eine Ganzzahl handelt:

function isInteger(s)
{
   return Math.ceil(s) == Math.floor(s);
}
Bat_Programmer
quelle
1

Das isNaN(" ")ist falsch, ist Teil des verwirrenden Verhaltens der isNaNglobalen Funktion aufgrund ihres Zwangs von Nicht-Zahlen zu einem numerischen Typ.

Von MDN :

Seit den frühesten Versionen der isNaNFunktionsspezifikation war ihr Verhalten für nicht numerische Argumente verwirrend. Wenn das Argument zumisNaN Funktion nicht vom Typ Number ist, wird der Wert zuerst zu einer Number gezwungen. Der resultierende Wert wird dann getestet, um festzustellen, ob dies der Fall ist NaN. Für Nicht-Zahlen, die beim Erzwingen eines numerischen Typs zu einem gültigen nicht-NaN-numerischen Wert führen (insbesondere die leere Zeichenfolge und die booleschen Grundelemente, die beim Erzwingen numerische Werte null oder eins ergeben), kann der "falsche" zurückgegebene Wert unerwartet sein. Die leere Zeichenfolge zum Beispiel ist sicherlich "keine Zahl".

Beachten Sie auch, dass es mit ECMAScript 6 jetzt auch das gibt Number.isNaN Methode gibt, die laut MDN:

Im Vergleich zur globalen isNaN()Funktion Number.isNaN()besteht nicht das Problem, den Parameter zwangsweise in eine Zahl umzuwandeln. Dies bedeutet, dass es jetzt sicher ist, Werte zu übergeben, die normalerweise konvertiert werden NaN, aber nicht den gleichen Wert wie NaN. Dies bedeutet auch, dass nur Werte der Typennummer zurückgegeben werden, die ebenfalls NaNzurückgegeben werdentrue .

Unglücklicherweise :

Sogar die ECMAScript 6- Number.isNaNMethode hat ihre eigenen Probleme, wie im Blog-Beitrag beschrieben - Behebung des hässlichen JavaScript- und ES6-NaN-Problems .

lucono
quelle
1

Die isNaNFunktion erwartet eine Zahl als Argument, sodass Argumente eines anderen Typs (in Ihrem Fall eine Zeichenfolge) in Zahl konvertiert werden, bevor die eigentliche Funktionslogik ausgeführt wird. (Beachten Sie, dassNaN auch ein Wert vom Typ Nummer ist!)

Übrigens. Dies gilt für alle integrierten Funktionen. Wenn sie ein Argument eines bestimmten Typs erwarten, wird das tatsächliche Argument mithilfe der Standardkonvertierungsfunktionen konvertiert. Es gibt Standardkonvertierungen zwischen allen Basistypen (Bool, String, Nummer, Objekt, Datum, Null, undefiniert).

Die Standardkonvertierung für Stringto Numberkann explizit mit aufgerufen werden Number(). So können wir das sehen:

  • Number(" ") bewertet zu 0
  • Number(" x") bewertet zu NaN

Vor diesem Hintergrund ist das Ergebnis der isNaNFunktion völlig logisch!

Die eigentliche Frage ist, warum die Standardkonvertierung von Zeichenfolgen in Zahlen so funktioniert. Die Konvertierung von Zeichenfolgen in Zahlen ist eigentlich dazu gedacht, numerische Zeichenfolgen wie "123" oder "17.5e4" in die entsprechenden Zahlen umzuwandeln. Die Konvertierung überspringt zuerst das anfängliche Leerzeichen (also ist "123" gültig) und versucht dann, die Reste als Zahl zu analysieren. Wenn es nicht als Zahl analysiert werden kann ("x" nicht), ist das Ergebnis NaN. Es gibt jedoch die explizite Sonderregel, dass eine Zeichenfolge, die leer ist oder nur Leerzeichen enthält, in 0 konvertiert wird. Dies erklärt also die Konvertierung.

Referenz: http://www.ecma-international.org/ecma-262/5.1/#sec-9.3.1

JacquesB
quelle
1

Ich habe diese kurze kleine Funktion geschrieben, um dieses Problem zu lösen.

function isNumber(val) {
     return (val != undefined && val != null && val.toString().length > 0 && val.toString().match(/[^0-9\.\-]/g) == null);
};

Es wird einfach nach Zeichen gesucht, die nicht numerisch (0-9), nicht '-' oder '.' Und nicht undefiniert, null oder leer sind, und es wird true zurückgegeben, wenn keine Übereinstimmungen vorhanden sind. :) :)

XtraSimplicity
quelle
Ein verspätetes Dankeschön dafür; Das hat mein Problem sehr gut gelöst.
Henry
1

Wie bereits erläutert isNaN, zwingt die Funktion die leere Zeichenfolge vor der Validierung in eine Zahl und ändert so eine leere Zeichenfolge in 0 (was eine gültige Zahl ist). Ich habe jedoch festgestellt, dass die parseIntFunktion zurückgegeben wird, NaNwenn versucht wird, eine leere Zeichenfolge oder eine Zeichenfolge mit nur Leerzeichen zu analysieren. Als solche scheint die folgende Kombination gut zu funktionieren:

if ( isNaN(string) || isNaN(parseInt(string)) ) console.log('Not a number!');

Diese Prüfung funktioniert für positive Zahlen, negative Zahlen und Zahlen mit einem Dezimalpunkt. Ich glaube, sie deckt alle gängigen numerischen Fälle ab.

Nadav
quelle
1

NaN ! == "keine Zahl"

NaN ist ein Wert vom Typ Nummer

Dies ist eine Definition von isNaN () in ECMAScript

1. Let num be ToNumber(number).
2. ReturnIfAbrupt(num).
3. If num is NaN, return true.
4. Otherwise, return false.

Versuchen Sie, einen beliebigen Wert in Zahl umzuwandeln.

Number(" ") // 0
Number("x") // NaN
Number(null) // 0

Wenn Sie feststellen möchten, ob der Wert lautet NaN, sollten Sie zunächst versuchen, ihn in einen Zahlenwert umzuwandeln.

bitfishxyz
quelle
0

Diese Funktion schien in meinen Tests zu funktionieren

function isNumber(s) {
    if (s === "" || s === null) {
        return false;
    } else {
        var number = parseInt(s);
        if (number == 'NaN') {
            return false;
        } else {
            return true;
        }
    }
}
bruno negrao
quelle
2
Ihre gesamte Funktion kann geschrieben werden:return !(s === "" || s === null || parseInt(s) == 'NaN');
ErikE
0

Wie wäre es mit

function isNumberRegex(value) {        
    var pattern = /^[-+]?\d*\.?\d*$/i;
    var match = value.match(pattern);
    return value.length > 0 && match != null;
}
Alexander Schmidt
quelle
0

Die in JavaScript integrierte isNaN- Funktion ist - wie standardmäßig zu erwarten - ein "Dynamic Type Operator". Daher alle Werte, die (während des DTC-Prozesses) ein einfaches true | ergeben können falsch wie "", " ", " 000", kann nicht NaN sein.

Dies bedeutet, dass das angegebene Argument zunächst wie folgt konvertiert wird :

function isNaNDemo(arg){
   var x = new Number(arg).valueOf();
   return x != x;
}

Erläuterung:

In der obersten Zeile des Funktionskörpers versuchen wir (zuerst), das Argument erfolgreich in ein Zahlenobjekt umzuwandeln. Und (zweitens) mit dem Punktoperator entfernen wir - zu unserer eigenen Bequemlichkeit - sofort den primitiven Wert des erstellten Objekts.

In der zweiten Zeile nehmen wir den im vorherigen Schritt erhaltenen Wert und den Vorteil der Tatsache, dass NaN mit nichts im Universum gleich ist, nicht einmal mit sich selbst, z. B.: NaN == NaN >> falseUm es endgültig (wegen Ungleichheit) mit sich selbst zu vergleichen .

Auf diese Weise liefert die Funktionsrückgabe nur dann true , wenn und nur wenn die angegebene Argumentrückgabe ein fehlgeschlagener Konvertierungsversuch in ein Zahlenobjekt ist, dh eine Zahl ohne Zahl; zB NaN.


isNaNstatic ()

Für einen Operator vom statischen Typ können wir jedoch - falls erforderlich und bei Bedarf - eine weitaus einfachere Funktion schreiben, z.

function isNaNstatic(x){   
   return x != x;
}

Vermeiden Sie den DTC insgesamt, damit das Argument false zurückgibt, wenn es nicht explizit eine NaN-Nummer ist. Testen Sie daher gegen Folgendes:

isNaNStatic(" x"); // will return false weil es immer noch eine Schnur ist.

Allerdings: isNaNStatic(1/"x"); // will of course return true.wie zum Beispiel isNaNStatic(NaN); >> true.

Aber im Gegensatz dazu isNaNist das, isNaNStatic("NaN"); >> falseweil es (das Argument) eine gewöhnliche Zeichenfolge ist.

ps: Die statische Version von isNaN kann in modernen Codierungsszenarien sehr nützlich sein. Und es kann sehr wohl einer der Hauptgründe sein, warum ich mir die Zeit genommen habe, dies zu veröffentlichen.

Grüße.

Bekim Bacaj
quelle
0

isNAN(<argument>)ist eine Funktion, um festzustellen, ob das angegebene Argument eine unzulässige Zahl ist. isNaNtypisiert die Argumente in den Typ Zahl. Wenn Sie überprüfen möchten, ob das Argument numerisch ist oder nicht? Bitte verwenden Sie die $.isNumeric()Funktion in jQuery.

Das heißt, isNaN (foo) entspricht isNaN (Number (foo)). Es akzeptiert aus offensichtlichen Gründen alle Zeichenfolgen mit allen Ziffern als Zahlen. Zum Beispiel.

isNaN(123) //false
isNaN(-1.23) //false
isNaN(5-2) //false
isNaN(0) //false
isNaN('123') //false
isNaN('Hello') //true
isNaN('2005/12/12') //true
isNaN('') //false
isNaN(true) //false
isNaN(undefined) //true
isNaN('NaN') //true
isNaN(NaN) //true
isNaN(0 / 0) //true
Om Sao
quelle
0

ich benutze das

    function isNotANumeric(val) {
    	if(val.trim && val.trim() == "") {
         return true;
      } else {
      	 return isNaN(parseFloat(val * 1));
      }
    }
    
    alert(isNotANumeric("100"));  // false
    alert(isNotANumeric("1a"));   // true
    alert(isNotANumeric(""));     // true
    alert(isNotANumeric("   "));  // true

kiranvj
quelle
0

Wenn , wenn bestimmte Zeichenfolge - Wert mit Leerzeichen Überprüfung oder " "wird isNaNvielleicht versuchen Zeichenfolge Validierung durchgeführt werden , beispielsweise:

// value = "123 " if (value.match(/\s/) || isNaN(value)) { // do something }

Channox
quelle