Domanda parseInt (null, 24) === 23 ... aspetta, cosa?


Va bene, quindi mi sono scontrato con parseInt per vedere come gestisce i valori non ancora inizializzati e mi sono imbattuto in questa gemma. Quanto segue accade per qualsiasi radix 24 o superiore.

parseInt(null, 24) === 23 // evaluates to true

L'ho provato su IE, Chrome e Firefox e sono tutti all'erta, quindi penso che debba essere incluso nelle specifiche da qualche parte. Una rapida ricerca su Google non mi ha dato alcun risultato quindi eccomi, sperando che qualcuno possa spiegare.

Ricordo di aver ascoltato un discorso di Crockford in cui stava dicendo typeof null === "object" a causa di una svista che fa in modo che Object e Null abbiano un identificatore di tipo quasi identico in memoria o qualcosa del genere, ma non riesco a trovarlo ora.

Provalo: http://jsfiddle.net/robert/txjwP/

modificare Correzione: un radix superiore restituisce risultati diversi, 32 restituisce 785077
Modifica 2 Da zzzzBov: [24...30]:23, 31:714695, 32:785077, 33:859935, 34:939407, 35:1023631, 36:1112745


tl; dr

Spiega perchè parseInt(null, 24) === 23 è una vera affermazione.


221
2018-06-23 19:48


origine


risposte:


Si sta convertendo null alla stringa "null" e provando a convertirlo. Per i radix da 0 a 23, non ci sono numeri che può convertire, quindi restituisce NaN. A 24 anni "n", la 14a lettera, viene aggiunta al sistema numerale. A 31 anni "u", la 21 ° lettera, viene aggiunta e l'intera stringa può essere decodificata. A 37 anni non esiste più un insieme numerico valido che può essere generato e viene restituito NaN.

js> parseInt(null, 36)
1112745

>>> reduce(lambda x, y: x * 36 + y, [(string.digits + string.lowercase).index(x) for x in 'null'])
1112745

235
2018-06-23 20:03



Mozilla ci dice:

funzione parseInt converte il suo primo   argomento a una stringa, lo analizza e   restituisce un numero intero o NaN. Se non è NaN,   il valore restituito sarà il decimale   rappresentazione intera del primo   argomento preso come un numero nel   Radix specificato (base). Ad esempio, a   la radice di 10 indica per convertire da   un numero decimale, 8 ottali, 16   esadecimale e così via. Per i raggi   sopra 10, le lettere dell'alfabeto   indicare numeri maggiori di 9. Per   esempio, per i numeri esadecimali (base   16), vengono usati da A a F.

In la spec, 15.1.2.2/1 ci dice che la conversione in stringa viene eseguita usando il built-in ToString, che (come per 9.8) produce "null" (da non confondere con toString, che darebbe "[object Window]"!).

Quindi, prendiamo in considerazione parseInt("null", 24).

Naturalmente, questa non è una stringa numerica base-24 per intero, ma "n" è: è decimale 23.

Ora, l'analisi si ferma dopo che il decimale 23 è stato estratto, perché "u"  non è trovato nel sistema base-24:

Se S contiene un personaggio che è   non una cifra di radix-R, quindi sia Z il   sottostringa di S composta da tutto   personaggi prima del primo tale   carattere; altrimenti, sia Z sia S. [15.1.2.2/11]

(Ed è per questo parseInt(null, 23) (e radiazioni inferiori) ti dà NaN piuttosto che 23: "n" non è nel sistema base-23.)


117
2018-06-23 20:03



Ignacio Vazquez-Abrams è corretto, ma lascia vedere esattamente come funziona...

A partire dal 15.1.2.2 parseInt (string , radix):

Quando viene chiamata la funzione parseInt,   i seguenti passi sono presi:

  • Sia inputString be ToString (stringa).
  • Sia S una sottostringa appena creata di inputString composta dal primo   personaggio che non è un   StrWhiteSpaceChar e tutti i personaggi   seguendo quel personaggio. (In altro   parole, rimuovi lo spazio bianco iniziale).
  • Lascia che il segno sia 1.
  • Se S non è vuoto e il primo carattere di S è un segno meno -, lascia   segno essere -1.
  • Se S non è vuoto e il primo carattere di S è un segno più + o a   segno meno -, quindi rimuovi il primo   personaggio di S.
  • Sia R = ToInt32 (radix).
  • Lascia che stripPrefix sia true.
  • Se R ≠ 0, allora a. Se R <2 o R> 36, quindi restituire NaN. b. Se R ≠ 16, let   stripPrefix essere falso.
  • Altro, R = 0 a. Lasciare R = 10.
  • Se stripPrefix è true, allora a. Se la lunghezza di S è almeno 2 e il   i primi due personaggi di S sono entrambi   "0x" o "0X", quindi rimuovere il primo   due caratteri da S e lascia R = 16.
  • Se S contiene un carattere che non è una cifra di radix-R, allora sia Z il   sottostringa di S composta da tutto   personaggi prima del primo tale   carattere; altrimenti, sia Z essere S.
  • Se Z è vuoto, restituire NaN.
  • Sia MathInt il valore intero matematico rappresentato da Z   in notazione Radix-R, usando le lettere   A-Z e a-z per cifre con valori 10   fino a 35. (Tuttavia, se R è 10 e Z   contiene più di 20 significativi   cifre, ogni cifra significativa dopo   il 20 può essere sostituito da una cifra 0,   a scelta dell'implementazione;   e se R non è 2, 4, 8, 10, 16 o   32, quindi mathInt potrebbe essere un   Approssimazione dipendente dall'implementazione   al valore intero matematico che   è rappresentato da Z in radix-R   notazione.)
  • Sia il numero il valore Numero per mathInt.
  • Segno di ritorno × numero.

NOTA parseInt può interpretare solo a   porzione principale di stringa come un   valore intero; ignora qualsiasi   personaggi che non possono essere interpretati   come parte della notazione di un numero intero,   e nessuna indicazione è data che nessuno   tali personaggi sono stati ignorati.

Ci sono due parti importanti qui. Ho sfidato entrambi. Quindi, prima di tutto, dobbiamo scoprire cosa sono toString rappresentazione di null è. Dobbiamo guardare Table 13 — ToString Conversions nella sezione 9.8.0 per tali informazioni:

enter image description here

Fantastico, quindi ora lo sappiamo toString(null) produce internamente a 'null' stringa. Ottimo, ma come gestisce esattamente le cifre (caratteri) che non sono valide all'interno della radice fornita?

Guardiamo sopra 15.1.2.2 e vediamo la seguente osservazione:

Se S contiene un personaggio che è   non una cifra di radix-R, quindi sia Z il   sottostringa di S composta da tutto   personaggi prima del primo tale   carattere; altrimenti, sia Z essere S.

Ciò significa che gestiamo tutte le cifre PRIMA della radix specificata e ignoriamo tutto il resto.

Fondamentalmente, facendo parseInt(null, 23) è la stessa cosa di parseInt('null', 23). Il u causa i due lÈ da ignorare (anche se SONO parte della radice 23). Pertanto, possiamo solo analizzare n, rendendo anche l'intera dichiarazione parseInt('n', 23). :)

Ad ogni modo, ottima domanda!


80
2018-06-23 20:17



parseInt( null, 24 ) === 23

È equivalente a

parseInt( String(null), 24 ) === 23

che è equivalente a

parseInt( "null", 24 ) === 23

Le cifre per la base 24 sono 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, ..., n.

Le specifiche della lingua dicono

  1. Se S contiene un carattere che non è una cifra di radix-R, allora sia Z la sottostringa di S che consiste di tutti i caratteri prima del primo di tali caratteri; altrimenti, sia Z essere S.

che è la parte che assicura che i letterali di tipo C siano simili 15L analizzare correttamente quindi quanto sopra è equivalente a

parseInt( "n", 24 ) === 23

"n" è la 23 ° lettera dell'elenco di cifre sopra.

Come volevasi dimostrare


33
2018-06-23 20:04



suppongo null viene convertito in una stringa "null". Così n è effettivamente 23 in 'base24' (stesso in 'base25' +), u non è valido in 'base24', quindi il resto della stringa null sarà ignorato. Ecco perché emette 23 fino a u diventerà valido in 'base31'.


15
2018-06-23 20:03



parseInt usa la rappresentazione alfanumerica, quindi in base-24 "n" è valido, ma "u" è un carattere non valido, quindi parseInt analizza solo il valore "n" ....

parseInt("n",24) -> 23

ad esempio, prova con questo:

alert(parseInt("3x", 24))

Il risultato sarà "3".


7
2018-06-23 20:06