Warum ist parseInt (8,3) == NaN und parseInt (16,3) == 1?

191

Ich lese diese aber ich bin verwirrt durch das, was in dem geschrieben steht ParseInt mit einem Radix Argument Kapitel

Tabelle der Ergebnisse von parseInt (_, 3)

Warum ist es das parseInt(8, 3)NaNund parseInt(16, 3)1?

AFAIK 8 und 16 sind nicht basen 3 Zahlen, so parseInt(16, 3)sollte zurückkehren NaNzu

die ersten zehn natürlichen Basis-3-Zahlen

Devid Farinelli
quelle
4
Ein weiteres Problem, das durch statische Typisierung (oder zumindest nicht implizite Konvertierung von Ganzzahlen in Zeichenfolgen) gelöst worden wäre: P
Navin
4
@Navin Dies hat nichts mit statischer oder dynamischer Eingabe zu tun (wie Sie selbst bemerken). Das Problem ist hier schwach im Gegensatz zu starkem Tippen.
Sven Marnach
12
Als ich den Titel dieser Frage sah, dachte ich mir: "Es liegt wahrscheinlich an Loljavascript." Als ich die Antworten sehe, beurteile ich meinen Instinkt als grundsätzlich richtig.
Ben Millwood

Antworten:

373

Dies ist etwas, worüber Menschen die ganze Zeit stolpern, selbst wenn sie davon wissen. :-) Sie sehen dies aus dem gleichen Grund. parseInt("1abc")Gibt 1 zurück: parseIntstoppt beim ersten ungültigen Zeichen und gibt alles zurück, was es zu diesem Zeitpunkt hat. Wenn keine gültigen Zeichen zum Parsen vorhanden sind, wird zurückgegeben NaN.

parseInt(8, 3)bedeutet " "8"in Basis 3 analysieren " (beachten Sie, dass die Zahl 8in eine Zeichenfolge konvertiert wird ; Details in der Spezifikation ). Aber in der Basis 3, die mit einem einstelligen Zahlen ist nur 0, 1und 2. Es ist, als würde man ihn bitten, "9"oktal zu analysieren . Da es keine gültigen Zeichen gab, hast du NaN.

parseInt(16, 3)fordert es auf, "16"in Basis 3 zu analysieren . Da es das analysieren kann 1, tut es dies und stoppt dann bei, 6weil es es nicht analysieren kann. Also kehrt es zurück 1.


Da diese Frage viel Aufmerksamkeit erhält und in den Suchergebnissen möglicherweise einen hohen Stellenwert hat, finden Sie hier eine Übersicht über die Optionen zum Konvertieren von Zeichenfolgen in Zahlen in JavaScript mit ihren verschiedenen Eigenheiten und Anwendungen (aus einer anderen Antwort von mir hier auf SO entnommen):

  • parseInt(str[, radix])- Konvertiert so viel wie möglich vom Anfang der Zeichenfolge in eine ganze Zahl (Ganzzahl), wobei zusätzliche Zeichen am Ende ignoriert werden. So parseInt("10x")ist es 10; das xwird ignoriert. Unterstützt eine optionale radix (Zahlenbasis) Argument, so parseInt("15", 16)ist 21( 15in hex). Wenn es keinen Radix gibt, wird eine Dezimalzahl angenommen, es sei denn, die Zeichenfolge beginnt mit 0x(oder 0X). In diesem Fall werden diese übersprungen und hexadezimal angenommen. (Einige Browser zu behandeln Strings mit Start 0als Oktal, das Verhalten nie angegeben wurde, und wurde speziell nicht erlaubt in der ES5 - Spezifikation.) Returns , NaNwenn keine parseable Stellen zu finden sind.

  • parseFloat(str)- Wie parseInt, aber Gleitkommazahlen und unterstützt nur Dezimalzahlen. Wiederum werden zusätzliche Zeichen in der Zeichenfolge ignoriert, ebenso parseFloat("10.5x")wie 10.5(das xwird ignoriert). Da nur Dezimalzahlen unterstützt werden, parseFloat("0x15")ist 0(weil das Parsen am endet x). Gibt zurück, NaNwenn keine analysierbaren Ziffern gefunden wurden.

  • Unär +, zB +str- ( zB implizite Konvertierung) Konvertiert die gesamte Zeichenfolge in eine Zahl unter Verwendung von Gleitkomma- und JavaScript-Standardnotationsnotation (nur Ziffern und Dezimalpunkt = Dezimalzahl; 0xPräfix = Hex; 0oPräfix = Oktal [ES2015 +]; einige Implementierungen erweitern sie eine Führung 0als oktal zu behandeln , aber nicht im strengen Modus). +"10x"ist , NaNweil das xist nicht ignoriert. +"10"ist 10, +"10.5"ist 10.5, +"0x15"ist 21, +"0o10"ist 8[ES2015 +]. Hat ein Gotcha: +""ist 0, nicht NaNwie man erwarten könnte.

  • Number(str)- Genau wie die implizite Konvertierung (z. B. wie +oben beschrieben), jedoch bei einigen Implementierungen langsamer. (Nicht, dass es wahrscheinlich wichtig wäre.)

TJ Crowder
quelle
8
Also parseIntzuerst toStringdas erste Argument verwenden? Das würde Sinn machen.
Evolutionxbox
16
@evolutionxbox: Ja, es ist der erste Schritt des parseIntAlgorithmus: ecma-international.org/ecma-262/7.0/…
TJ Crowder
5
Ich nehme an, 123e-2gibt es, 1da es 1.23zuerst wird und dann das Parsen am Dezimalpunkt stoppt?
Ilkkachu
6
"Das ist etwas, worüber die Leute die ganze Zeit stolpern, auch wenn sie davon wissen" -> bin ich der einzige, der denkt, dass dies ein Fehler sein sollte? Wenn Sie dies beispielsweise in Java tun, erhalten Sie NumberFormatExceptionjedes Mal eine.
Wim Deblauwe
4
@SvenMarnach: Dieser Teil von parseInt(das erste Argument zum String zwingen) macht Sinn. Der Zweck von parseIntbesteht darin, eine Zeichenfolge auf eine ganze Zahl zu analysieren . Wenn Sie ihm also etwas geben, das keine Zeichenfolge ist, ist es sinnvoll, zunächst die Zeichenfolgendarstellung zu erhalten. Was sie tut , nach , dass eine ganze ‚nother Geschichte ...
TJ Crowder
54

Aus dem gleichen Grund, dass

>> parseInt('1foobar',3)
<- 1

In dem Dokument , parseIntnimmt einen String. Und

Wenn der String kein String ist, wird er in einen String konvertiert

Also 16, 8oder '1foobar'wird zuerst in einen String konvertiert.

Dann

Wenn Sie parseIntauf ein Zeichen stoßen, das im angegebenen Radix keine Ziffer ist, werden es und alle nachfolgenden Zeichen ignoriert

Das heißt, es konvertiert bis dahin, wo es kann. Die 6, 8und foobarwerden ignoriert, und nur das, was vor sich gewandelt. Wenn es nichts gibt, NaNwird zurückgegeben.

njzk2
quelle
0
/***** Radix 3: Allowed numbers are [0,1,2] ********/
parseInt(4, 3); // NaN - We can't represent 4 using radix 3 [allowed - 0,1,2]

parseInt(3, 3); // NaN - We can't represent 3 using radix 3 [allowed - 0,1,2]

parseInt(2, 3); // 2   - yes we can !

parseInt(8, 3); // NaN - We can't represent 8 using radix 3 [allowed - 0,1,2]

parseInt(16, 3); // 1  
//'16' => '1' (6 ignored because it not in [0,1,2])    

/***** Radix 16: Allowed numbers/characters are [0-9,A-F] *****/ 
parseInt('FOX9', 16); // 15  
//'FOX9' => 'F' => 15 (decimal value of 'F')
// all characters from 'O' to end will be ignored once it encounters the out of range'O'
// 'O' it is NOT in [0-9,A-F]

Einige weitere Beispiele:

parseInt('45', 13); // 57
// both 4 and 5 are allowed in Radix is 13 [0-9,A-C]

parseInt('1011', 2); // 11 (decimal NOT binary)

parseInt(7,8); // 7
// '7' => 7 in radix 8 [0 - 7]

parseInt(786,8); // 7 
// '78' => '7' => 7 (8 & next any numbers are ignored bcos 8 is NOT in [0-7])

parseInt(76,8); // 62 
// Both 7 & 6 are allowed '76' base 8 decimal conversion is 62 base 10 
SridharKritha
quelle