Skip to content

Instantly share code, notes, and snippets.

@Cycymomo
Last active December 31, 2015 03:29
Show Gist options
  • Save Cycymomo/7928122 to your computer and use it in GitHub Desktop.
Save Cycymomo/7928122 to your computer and use it in GitHub Desktop.
parseInt is evil

parseInt est pratique. Il est embarqué nativement dans JavaScript et permet de convertir une chaîne de caractère (String) en entier. JavaScript étant permessif historiquement1, n'importe quelle valeur peut lui être passée. Il va silencieucesment la convertir en String (à l'aide de la méthode toString embarquée nativement dans chaque instance d'Object), puis effectuer le parseInt.

D'où :

parseInt("0.0000008", 10); // 0, ok tout va bien
parseInt(0.0000008, 10); // 8 WTF ?!

WTF ?!?

Etapes (grossières) de parseInt(nb) sous le capot 2 :

var nbTemp = toString(nb);
parseInt(nbTemp);

Le problème vient de toString(). En effet, cette fonction native transforme 3 les nombres décimaux à plus de six décimales après la virgule en cette notation : Xe-n (exemple : 8e-7).

Donc, avec nb = 0.0000008 :

var nbTemp = toString(0.0000008); // "8e-7"
parseInt("8e-7"); // 8

Conseils

N'utiliser parseInt qu'avec des chaînes. En fait, parseInt aurait dû être nommé parseStringToInt().

Une solution possible, utiliser la spéc. de la prochaine norme ES6 : Number.isNumber

function parseIntSafe(n) {
  return typeof n === "number" && isFinite(n) && n >= (Number.MIN_SAFE_INTEGER || -9007199254740991) && n <= (Number.MAX_SAFE_INTEGER || 9007199254740992) && Math.floor(n) === n? n : NaN;
}

// Integers
console.log(parseIntSafe(4597));
console.log(parseIntSafe(8e3));
console.log(parseIntSafe(1e19));

// !Integers
console.log(parseIntSafe("4598"));
console.log(parseIntSafe(Number.MAX_VALUE));
console.log(parseIntSafe(Infinity));
console.log(parseIntSafe(NaN));
console.log(parseIntSafe({}));
console.log(parseIntSafe(false));
console.log(parseIntSafe(true));
console.log(parseIntSafe(null));
console.log(parseIntSafe(undefined));
console.log(parseIntSafe("lol"));
console.log(parseIntSafe("9.489"));
console.log(parseIntSafe("4,579,312"));
console.log(parseIntSafe("5,2"));
console.log(parseIntSafe("8e3"));
console.log(parseIntSafe(".5"));

Ou alors, préférez une méthode de Golfing qui fonctionne quelque soit le type :

"0.0000008" ^ 0 // string (primitive)
~~0.0000008 // number (primitive)
new String('0.0000008') >> 0 // object wrapper string
String('0.0000008') << 0 // string (primitive)
new Number(0.0000008) | 0 // object wrapper number

Avez-vous une autre méthode pour parser des entiers en JavaScript ?

Sources :

  1. Lien vers autre article
  2. ES5 sec-15.1.2.2 parseInt (string , radix)
  3. ES5 sec-9.8.1 ToString Applied to the Number Type
  4. harmony:number.isinteger
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment