286 votes

Comment puis-je travailler autour de JavaScript ' comportement d’octal parseInt s ?

Essayez d'exécuter les opérations suivantes dans le JavaScript:

parseInt('01'); //equals 1
parseInt('02'); //equals 2
parseInt('03'); //equals 3
parseInt('04'); //equals 4
parseInt('05'); //equals 5
parseInt('06'); //equals 6
parseInt('07'); //equals 7
parseInt('08'); //equals 0 !!
parseInt('09'); //equals 0 !!

J'ai juste appris à la dure que JavaScript pense que le zéro indique une octal entier, et depuis il n'y a pas de "8" ou "9" dans la base 8, la fonction renvoie zéro. Il aime ou pas, c'est par la conception.

Quelles sont les solutions?

Remarque: Par souci d'exhaustivité, je suis sur le point de publier une solution, mais c'est une solution que je déteste, donc s'il vous plaît poster d'autres/de meilleures réponses.


Mise à jour: la 5ème Édition de la norme JavaScript (ECMA-262) introduit une modification importante qui élimine ce problème. Mozilla a une bonne écriture-up.

332voto

Paolo Bergantino Points 199336

Il s’agit d’une chasse aux sorcières Javascript commun avec une solution simple :

Juste préciser la base, ou « radix », comme suit :

Vous pouvez également utiliser le numéro:

63voto

xfix Points 2890

Tout d'abord, vous n'avez vraiment pas besoin d' parseInt() dans la plupart des cas. C'est l'algorithme est plein de diverses bizarreries, l' 0 préfixe est même interdit par la spécification ("la spécification de la fonction parseInt ne permet plus implémentations pour traiter les Chaînes de caractères commençant par un 0 caractères que les valeurs octales."), mais il faudra un certain temps pour changer de navigateur comportements (même si je suis sûr que personne ne l'utilisez octals intentionnellement en parseInt()). Et Internet Explorer 6 ne changera jamais (Internet Explorer 9 toutefois supprimé le support octals en parseInt()). L'algorithme utilisé par habitude, elle ne fonctionne plus que vous le souhaitez. Dans certains cas, c'est une mauvaise idée.

  1. Premier argument est converti en chaîne si elle n'est pas déjà fait.
  2. Découper le nombre, ' 4' devient '4'.
  3. Vérifiez si la chaîne commence par - ou + et de supprimer ce caractère. Si c'était - faire de sortie négative.
  4. Convertir radix entier.
  5. Si radix est - 0 ou NaN d'essayer de deviner de radix. Il signifie à la recherche (insensible à la casse) pour 0x (non-standard) 0. Si le préfixe n'a pas été trouvé, 10 est utilisé (et c'est ce que vous le plus probable).
  6. Si radix est - 16 de strip - 0x depuis le début si elle existe.
  7. Trouver le premier caractère qui n'est pas à portée de radix.
  8. Si il n'y a rien avant le premier caractère qui n'était pas dans la gamme de base, de revenir NaN.
  9. Convertir le nombre décimal jusqu'à ce que le premier caractère qui n'est pas dans la gamme.

    Par exemple, parseInt('012z', 27) donne 0 * Math.pow(27, 2) + 1 * Math.pow(27, 1) + 2 * Math.pow(27, 0).

L'algorithme lui-même n'est pas très rapide, mais la performance varie (optimisations de faire des merveilles). J'ai mis en test sur JSPerf et les résultats sont intéressants. + et ~~ sont les plus rapides, à l'exception de Chrome où parseFloat() est en quelque sorte de manière plus rapide que les autres options (2 à 5 fois plus rapide que les autres options, où l' + est en fait 5 fois plus lent). Dans Firefox, ~~ test est très rapide dans certains cas, j'ai Infinity des cycles.

L'autre chose, c'est la décision correcte. parseInt(), ~~ et parseFloat() font des erreurs dans le silence. Dans le cas d' parseInt() et parseFloat() caractères sont ignorés après caractère non valide - vous pouvez l'appeler une fonction (dans la plupart des cas, il est anti-fonctionnalité pour moi, tout comme switch états fallthrough) et si vous en avez besoin, utilisez l'un de ceux-ci. Dans le cas d' ~~ il moyen de revenir 0, alors soyez prudent.

Dans certains cas, parseInt() pourrait vous blesser. Mal. Par exemple, si le nombre est si grand qu'il est écrit en notation exponentielle. Utiliser Math méthodes ensuite.

parseInt(2e30); // will return 2

De toute façon, à la fin je veux faire une liste des méthodes pour convertir des chaînes en nombres (les nombres entiers et les flottants). Ils ont différents usages et vous pouvez être intéressé quant à la méthode à utiliser. Dans la plupart des cas, le plus simple est +number méthode, utilisez si vous le pouvez. Quoi que vous fassiez (sauf pour la première méthode), tous devraient donner des résultats corrects.

parseInt('08', 10); // 8
+'08';              // 8
~~'08';             // 8
parseFloat('08');   // 8
Number('08');       // 8
new Number('08');   // 8... I meant Object container for 8
Math.ceil('08');    // 8

parseInt(number)

Ne l'utilisez pas. Simple que cela. Utiliser parseInt(number, 10) ou cette solution de contournement qui va automatiquement corriger parseInt fonction. Veuillez noter que cette solution de contournement ne fonctionne pas dans JSLint. Veuillez ne pas se plaindre à ce sujet.

(function () {
    "use strict";
    var oldParseInt = parseInt;
    // Don't use function parseInt() {}. It will make local variable.
    parseInt = function (number, radix) {
        return oldParseInt(number, radix || 10);
    };
}());

parseInt(number, radix)

parseInt convertit l'argument des nombres à l'aide mentionnée ci-dessus de l'algorithme. Éviter de l'utiliser sur de grands entiers comme il peut faire des résultats incorrects dans de tels cas parseInt(2e30). Aussi, ne jamais donner comme argument Array.prototype.map ou Underscore.js variante de ce que vous pouvez obtenir des résultats bizarres (essayez ['1', '2', '3'].map(parseInt) si vous voulez (pour plus d'explications, remplacez - parseInt avec console.log)).

L'utiliser quand:

  1. Lorsque vous avez besoin de lire les données écrites dans différents radix.
  2. Vous devez ignorer les erreurs (par exemple, un changement 123px de 123)

Sinon, l'utilisation d'autres méthodes sécuritaires (si vous avez besoin d'entier, d'utilisation Math.floor plutôt).

+number

+ préfixe (+number) convertit le nombre de flotter. En cas d'erreur, il renvoie NaN vous pouvez comparer par isNaN() ou simplement en number !== number (il doit renvoyer true seulement pour l' NaN). Il est très rapide dans l'Opéra.

L'utiliser, sauf si vous voulez des fonctionnalités spécifiques d'autres types.

~~number

~~ est un hack qui utilise ~ deux fois sur l'entier. En tant que ~ opération au niveau du bit peut être fait uniquement pour les entiers, le numéro est automatiquement converti. La plupart des navigateurs ont des optimisations pour ce cas. Comme les opérations bit à bit seulement le travail ci-dessous Math.pow(2, 32) ne jamais utiliser cette méthode avec de grands nombres. C'est hyper rapide sur SpiderMonkey moteur.

L'utiliser quand:

  1. Vous écrivez du code, où la performance est importante pour SpiderMonkey (comme FireFox plugins) et vous n'avez pas besoin de détection d'erreur.
  2. Vous avez besoin d'entier et de soins résultant JavaScript taille.

parseFloat(number)

parseFloat() fonctionne comme + avec la seule exception à ce processus de nombre jusqu'au premier caractère invalide au lieu de renvoyer NaN. Il est très rapide (mais pas aussi vite que ~~ sur Firefox) en V8. Contrairement aux parseInt variation, il devrait être à l'abri avec Array.prototype.map.

L'utiliser quand:

  1. Vous êtes en train de rédiger la performance est critique de code pour Node.js ou vous êtes en train de rédiger Google Chrome plugins (V8).
  2. Vous devez ignorer les erreurs (par exemple, un changement 42.13px de 42.13)

Number(number)

L'éviter. Il fonctionne comme + préfixe et est généralement plus lent. La seule utilisation où il pourrait être utile est la fonction de rappel pour l' Array.prototype.map - vous ne pouvez pas utiliser + que le rappel.

new Number(number)

L'utiliser quand vous en avez besoin pour embrouiller tout le monde avec 0 étant truthy valeur et avoir typeof de 'number'. Sérieusement, n'en ont pas.

Mathématiques méthodes, comme Math.ceil(number)

Utilisez-la lorsque vous avez besoin d'entier comme il est plus sûr que d' parseInt() par pas ignorant des caractères inattendus. Veuillez noter que, techniquement, il implique de longues conversion de chaîne → float → integer → float (les numéros sont en JavaScript flotteurs) - mais la plupart des navigateurs ont optimisations, donc, habituellement, il n'est pas visible. Il est également sans danger avec Array.prototype.map.

44voto

Karl Guertin Points 2206

Si vous connaissez votre valeur sera dans la plage d’entiers signés 32 bits, puis `` va faire la bonne chose dans tous les scénarios.

Si vous ne chercher pas binaire ( ), la spécification nécessite une conversion de « ToInt32 » pour l’argument qui effectue la conversion évidente en Int32 et est spécifié pour contraindre les valeurs à zéro.

Oui, c’est incroyablement hackers mais est tellement pratique...

24voto

Portman Points 15878

De la documentation parseInt, utilisez l’argument radix facultatif pour spécifier la base 10 :

Cela me paraît pédant, déroutant et verbose (vraiment, un argument supplémentaire dans chaque parseInt unique ?) donc j’espère qu’il y a une meilleure façon.

10voto

RichieHindle Points 98544

Spécifiez la base :

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