Perché parseInt (8,3) == NaN e parseInt (16,3) == 1?


191

Sto leggendo questo, ma sono confuso da ciò che è scritto nel parseInt con un capitolo argomento radix

tabella dei risultati di parseInt (_, 3)

Perché è parseInt(8, 3)NaNe parseInt(16, 3)1?

AFAIK 8 e 16 non sono numeri di base 3, quindi parseInt(16, 3)dovrebbero tornare NaNanche loro

i primi dieci numeri naturali base-3


4
Ancora un altro problema che sarebbe stato risolto digitando staticamente (o almeno non convertendo implicitamente interi in stringhe): P
Navin,

4
@Navin Questo non ha nulla a che fare con la digitazione statica rispetto a quella dinamica (come noti te stesso). Il problema qui è debole rispetto alla digitazione forte.
Sven Marnach,

12
Quando ho visto il titolo di questa domanda ho pensato tra me e me "è probabilmente perché loljavascript". Vedendo le risposte, giudico il mio istinto sostanzialmente corretto.
Ben Millwood,

Risposte:


373

Questo è qualcosa su cui le persone inciampano continuamente, anche quando ne sono a conoscenza. :-) Stai vedendo questo per lo stesso motivo parseInt("1abc")restituisce 1: si parseIntferma al primo carattere non valido e restituisce tutto ciò che ha a quel punto. Se non ci sono caratteri validi da analizzare, ritorna NaN.

parseInt(8, 3)significa "analisi "8"in base 3" (nota che converte il numero 8in una stringa; dettagli nelle specifiche ). Ma in base 3, i numeri a una cifra sono solo 0, 1e 2. È come chiedergli di analizzare "9"nell'ottale. Poiché non vi erano nessun caratteri validi, hai NaN.

parseInt(16, 3)lo sta chiedendo di analizzare "16"in base 3. Dal momento che può analizzare il 1, lo fa, e poi si ferma al 6perché non può analizzarlo. Quindi ritorna 1.


Dal momento che questa domanda sta suscitando molta attenzione e potrebbe classificare molto nei risultati di ricerca, ecco una carrellata di opzioni per convertire stringhe in numeri in JavaScript, con le loro varie idiosincrasie e applicazioni (sollevate da un'altra mia risposta qui su SO):

  • parseInt(str[, radix])- Converte il più possibile l'inizio della stringa in un numero intero (intero), ignorando i caratteri extra alla fine. Così parseInt("10x")è 10; la xviene ignorato. Supporta un argomento opzionale radix (base di numeri), così parseInt("15", 16)come 21( 15in esadecimale). Se non c'è radix, assume il decimale a meno che la stringa non inizi con 0x(o 0X), nel qual caso salta quelli e assume esadecimali. (Alcuni browser erano soliti trattare le stringhe che iniziano con 0come ottale; tale comportamento non è mai stato specificato ed è stato espressamente vietato nella specifica ES5.) Restituisce NaNse non viene trovata alcuna cifra analizzabile.

  • parseFloat(str)- Mi piace parseInt, ma fa numeri in virgola mobile e supporta solo i decimali. Anche in questo caso i caratteri extra sulla stringa vengono ignorati, così parseFloat("10.5x")come 10.5( xviene ignorato). Poiché è supportato solo il decimale, parseFloat("0x15")è 0(perché l'analisi termina in corrispondenza del x). Restituisce NaNse non viene trovata alcuna cifra analizzabile.

  • Unario +, ad es. +str- (Ad esempio, conversione implicita) Converte l' intera stringa in un numero usando il virgola mobile e la notazione numerica standard di JavaScript (solo cifre e un punto decimale = decimale; 0xprefisso = esadecimale; 0oprefisso = ottale [ES2015 +]; alcune implementazioni lo estendono trattare un leader 0come ottale, ma non in modalità rigorosa). +"10x"è NaNperché nonx viene ignorato. è , è , è , è [ES2015 +]. Ha un gotcha: è , non come ti aspetteresti.+"10"10+"10.5"10.5+"0x15"21+"0o10"8+""0NaN

  • Number(str)- Esattamente come la conversione implicita (ad esempio, come l'unario +sopra), ma più lento su alcune implementazioni. (Non che sia probabile che importi.)


8
Quindi, per parseIntprima cosa usa toStringil primo argomento? Ciò avrebbe senso.
evolutionxbox

16
@evolutionxbox: Sì, è il primo passo parseIntdell'algoritmo: ecma-international.org/ecma-262/7.0/…
TJ Crowder

5
Suppongo 123e-2dia 1dato che si trasforma in 1.23prima, e quindi l'analisi si ferma al punto decimale?
ilkkachu,

6
"Questo è qualcosa che le persone inciampano continuamente, anche quando ne sono a conoscenza" -> Sono l'unico che pensa che questo dovrebbe essere un bug? Fare lo stesso in Java, ad esempio, ti darà una NumberFormatExceptionvolta ogni volta.
Wim Deblauwe,

4
@SvenMarnach: quella parte di parseInt(costringere il primo argomento alla stringa) ha senso. Lo scopo di parseIntè analizzare una stringa in un numero intero. Quindi, se gli dai qualcosa che non è una stringa, è logico iniziare con la rappresentazione della stringa. Quello che fa dopo è tutta un'altra storia ...
TJ Crowder,

54

Per lo stesso motivo

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

Nel documento , parseIntaccetta una stringa. E

Se stringa non è una stringa, viene convertita in una stringa

Quindi 16, 8o '1foobar'viene prima convertito in stringa.

Poi

Se parseIntincontra un personaggio che non è un numero nella radice specificata, lo ignora e tutti i personaggi successivi

Significa che converte fino a dove può. I 6, 8e foobarvengono ignorati e viene convertito solo ciò che è prima. Se non c'è nulla, NaNviene restituito.


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]

Alcuni altri esempi:

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 
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.