226 votes

parseInt(null, 24) === 23... attendez, quoi?

Bon, alors j'ai été déconner avec parseInt pour voir comment il gère les valeurs pas encore initialisé et je suis tombé sur ce petit bijou. Ci-dessous se produit en radix 24 ou au-dessus.

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

Je l'ai testé sous IE, Chrome et Firefox, et ils sont tous d'alerte vrai, donc, je pense qu'il doit être dans la spécification quelque part. Une rapide recherche sur Google ne m'a pas donné tous les résultats alors je suis ici en espérant que quelqu'un peut expliquer.

Je me souviens de l'écoute d'un Crockford discours où il disait typeof null === "object" en raison d'un oubli Objet causant et Nul d'avoir un quasi identiques identificateur de type de mémoire ou quelque chose le long de ces lignes, mais je ne trouve pas que la vidéo maintenant.

Essayez-le: http://jsfiddle.net/robert/txjwP/

Edit Correction: une plus grande radix renvoie des résultats différents, 32 retourne 785077
Edit 2 De zzzzBov: [24...30]:23, 31:714695, 32:785077, 33:859935, 34:939407, 35:1023631, 36:1112745


tl;dr

Expliquer pourquoi parseInt(null, 24) === 23 est un énoncé vrai.

239voto

Ignacio Vazquez-Abrams Points 312628

C'est la conversion d' null à la chaîne de caractères "null" et d'essayer de le convertir. Pour radixes de 0 à 23, il n'y a pas de chiffres il est possible de convertir, de sorte qu'il retourne NaN. À 24 ans, "n", la 14e lettre, est ajouté au système de numération. Au 31, "u", la 21e lettre, est ajouté et l'ensemble de la chaîne peut être décodé. À 37 sur il n'est plus valide, chiffre qui peut être généré et NaN est renvoyé.

js> parseInt(null, 36)
1112745

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

118voto

Mozilla nous dit:

la fonction parseInt convertit sa première argument une chaîne de caractères, l'analyse, et renvoie un nombre entier ou NaN. Sinon NaN, la valeur retournée sera la virgule représentation entière de la première argument pris comme un nombre dans la spécifié radix (de base). Par exemple, un radix de 10 indique de convertir à partir de un nombre décimal, 8 octal, 16 hexadécimal, et ainsi de suite. Pour radices au-dessus de 10, les lettres de l'alphabet indiquer des chiffres supérieurs à 9. Pour exemple, pour les nombres hexadécimaux (de base 16), A et F sont utilisés.

Dans la spec, 15.1.2.2/1 nous dit que la conversion de chaîne est effectuée en utilisant le haut- ToString, qui (comme par 9.8) les rendements en "null" (à ne pas confondre avec toString, ce qui donnerait "[object Window]"!).

Donc, nous allons considérer parseInt("null", 24).

Bien sûr, ce n'est pas une base de 24 chaîne numérique en entier, mais "n" est: il est décimal 23.

Maintenant, l'analyse s'arrête après la virgule 23 est sorti, parce qu' "u" n'est pas trouvé dans la base 24 du système:

Si S contient un caractère qui est pas un radix-R chiffre, soit Z le sous-chaîne de S, composé de toutes les les caractères avant le premier de ces caractère; sinon, laissez-Z S. [15.1.2.2/11]

(Et c'est pourquoi, parseInt(null, 23) (et donc moins de radices) vous donne NaN plutôt que de 23 "n" n'est pas dans la base-23).

79voto

David Titarenco Points 17148

Ignacio Vazquez-Abrams est correct, mais permet de voir exactement comment il fonctionne...

D' 15.1.2.2 parseInt (string , radix):

Lorsque le parseInt fonction est appelée, les mesures suivantes sont prises:

  • Laissez inputString être ToString(string).
  • Soit S une nouvelle chaîne de inputString composé de la première caractère qui n'est pas un StrWhiteSpaceChar et tous les personnages suite à ce personnage. (En d'autres mots, supprimer l'espace blanc.)
  • Laisser signe sera de 1.
  • Si S n'est pas vide et le premier caractère de S est un signe moins -, laissez signe de -1.
  • Si S n'est pas vide et le premier caractère de S est un signe + ou un signe -, puis supprimer le premier personnage de S.
  • Soit R = ToInt32(radix).
  • Laissez stripPrefix être vrai.
  • Si R ≠ 0, un. Si R < 2 ou R > 36, puis retour NaN. b. Si R ≠ 16, laissez stripPrefix être faux.
  • Autre chose, R = 0 un. Soit R = 10.
  • Si stripPrefix est vrai, alors une. Si la longueur de S est au moins 2 et de la les deux premiers caractères de S sont soit "0x" ou "0X", puis supprimer le premier deux personnages de la S et soit R = 16.
  • Si S contient un caractère qui n'est pas un radix-R chiffre, soit Z le sous-chaîne de S, composé de toutes les les caractères avant le premier de ces caractère; sinon, laissez-Z S.
  • Si Z est vide, le retour de NaN.
  • Laissez mathInt être la mathématique valeur entière qui est représenté par Z dans radix-R notation, à l'aide de lettres A-Z et a-z pour les chiffres avec les valeurs 10 par le biais de 35. (Cependant, si R est de 10 et Z contient plus de 20 significative chiffres, chaque chiffre significatif après le 20ème peut être remplacé par un 0 chiffres, au gré de la mise en œuvre; et si R n'est pas 2, 4, 8, 10, 16, ou 32, puis mathInt peut être un dépendant de l'implémentation rapprochement pour les mathématiques de la valeur entière est représenté par Z dans radix-R la notation.)
  • Laissez-le nombre le Nombre de la valeur pour mathInt.
  • Retour signe × nombre.

NOTE parseInt peut interpréter seulement un leader de la partie de la chaîne comme une valeur d'entier; il ignore tout les caractères qui ne peuvent pas être interprétées dans le cadre de la notation d'un nombre entier, et aucune indication n'est donnée que tout ces caractères ont été ignorés.

Il y a deux parties importantes ici. J'ai mis en caractères gras les deux d'entre eux. Alors tout d'abord, nous devons savoir ce que l' toString de la représentation de l' null . Nous devons examiner Table 13 - ToString Conversions dans la section 9.8.0 pour cette information:

enter image description here

Grande, alors maintenant, nous savons que ce toString(null) en interne donne un 'null' chaîne de caractères. Grande, mais exactement comment ça poignée de chiffres (caractères) qui ne sont pas valides dans la base fournie?

Nous regardons au-dessus de 15.1.2.2 et nous voyons l'observation suivante:

Si S contient un caractère qui est pas un radix-R chiffre, soit Z le sous-chaîne de S, composé de toutes les les caractères avant le premier de ces caractère; sinon, laissez-Z S.

Cela signifie que nous nous occupons de tous les chiffres AVANT la spécifié radix et ignorer tout le reste.

En gros, faire parseInt(null, 23) est la même chose que parseInt('null', 23). L' u entraîne les deux ls'être ignoré (même s'ils font partie de la base 23). Par conséquent, nous ne pouvons analyser uniquement n, faisant de l'ensemble de la déclaration synonyme d' parseInt('n', 23). :)

De toute façon, la grande question!

33voto

Mike Samuel Points 54712
parseInt( null, 24 ) === 23

Est équivalent à

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

ce qui est équivalent à

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

Les chiffres de la base de 24 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, ..., n.

Le langage de spécification dit

  1. Si S contient un caractère qui n'est pas un radix-R chiffre, soit Z le sous-chaîne de S constituée de tous les caractères avant le premier de ces caractères; sinon, laissez-Z S.

qui est la partie qui assure C-style les littéraux entiers comme 15L analyser correctement, ainsi, le ci-dessus est équivalente à

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

"n" est la 23-ème lettre de l'chiffres de la liste ci-dessus.

Q. E. D.

16voto

Floern Points 11484

Je suppose null est converti en une chaîne de caractères "null". Donc, n est en fait 23 dans 'base24" (même dans "base25'+), u n'est pas valide dans 'base24' de sorte que le reste de la chaîne null sera ignoré. C'est pourquoi il sorties 23 jusqu' u entrera en vigueur dans 'base31'.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X