parseInt vs unaire plus, quand utiliser lequel?

149

Quelles sont les différences entre cette ligne:

var a = parseInt("1", 10); // a === 1

et cette ligne

var a = +"1"; // a === 1

Ce test jsperf montre que l'opérateur unaire est beaucoup plus rapide dans la version actuelle de chrome, en supposant que ce soit pour node.js !?

Si j'essaie de convertir des chaînes qui ne sont pas des nombres, les deux renvoient NaN:

var b = parseInt("test" 10); // b === NaN
var b = +"test"; // b === NaN

Alors, quand devrais-je préférer utiliser parseIntle plus unaire (en particulier dans node.js) ???

edit : et quelle est la différence avec l'opérateur double tilde ~~?

ici et maintenant78
la source
1
Benchmark jsperf.com/parseint-vs-unary-operator
Roko C. Buljan

Réponses:

169

Veuillez consulter cette réponse pour un ensemble plus complet de cas




Eh bien, voici quelques différences que je connais:

  • Une chaîne vide ""évalue à a 0, tandis que l' parseIntévalue à NaN. IMO, une chaîne vide doit être un NaN.

    +'' === 0;              //true
    isNaN(parseInt('',10)); //true
  • L'unaire +agit plus comme parseFloatpuisqu'il accepte également les décimales.

    parseIntd'autre part, arrête l'analyse quand il voit un caractère non numérique, comme le point qui est censé être un point décimal ..

    +'2.3' === 2.3;           //true
    parseInt('2.3',10) === 2; //true
  • parseIntet parseFloatanalyse et construit la chaîne de gauche à droite . S'ils voient un caractère invalide, il renvoie ce qui a été analysé (le cas échéant) comme un nombre, et NaNsi aucun n'a été analysé comme un nombre.

    L'unaire, +en revanche, retournera NaNsi la chaîne entière n'est pas convertible en nombre.

    parseInt('2a',10) === 2; //true
    parseFloat('2a') === 2;  //true
    isNan(+'2a');            //true
  • Comme vu dans le commentaire de @Alex K. , parseIntet parseFloatanalysera par caractère. Cela signifie que les notations hexadécimales et exposantes échoueront car les xet esont traités comme des composants non numériques (au moins sur base10).

    +Cependant, l' unaire les convertira correctement.

    parseInt('2e3',10) === 2;  //true. This is supposed to be 2000
    +'2e3' === 2000;           //true. This one's correct.
    
    parseInt("0xf", 10) === 0; //true. This is supposed to be 15
    +'0xf' === 15;             //true. This one's correct.
Joseph
la source
6
Aussi lors de l'utilisation d'un radix+"0xf" != parseInt("0xf", 10)
Alex K.
J'aime le plus votre réponse jusqu'à présent, pouvez-vous également expliquer quelle est la différence avec l'opérateur double tilde ~~?
hereandnow78
@ hereandnow78 Cela serait expliqué ici . C'est l'équivalent au niveau du bit de Math.floor(), qui coupe essentiellement la partie décimale.
Joseph le
4
En fait, ce "2e3"n'est pas une représentation entière valide pour 2000. C'est un nombre à virgule flottante valide cependant: parseFloat("2e3")donnera correctement 2000la réponse. Et "0xf"nécessite au moins la base 16, c'est pourquoi parseInt("0xf", 10)renvoie 0, alors que parseInt("0xf", 16)renvoie la valeur de 15 que vous attendiez.
Bart
2
@Joseph the Dreamer et @ hereandnow78: le double tilde coupe la partie décimale du nombre, tandis que Math.floor renvoie le nombre inférieur le plus proche. Ils fonctionnent de la même manière pour un nombre positif, mais Math.floor(-3.5) == -4et ~~-3.5 == -3.
Albin
261

La table de conversion ultime quel que soit en nombre: Table de conversion

georg
la source
2
Veuillez ajouter "NaN"à ce tableau.
chharvey
Cela peut valoir la peine d'ajouter une isNaNcolonne à cette table: par exemple, isNaN("")est faux (c'est-à-dire qu'il est considéré comme un nombre), mais parseFloat("")est NaN, ce qui peut être un piège, si vous essayez d'utiliser isNaNpour valider l'entrée avant de la passer àparseFloat
Retsam
Vous devez également ajouter '{valueOf: function(){return 42}, toString: function(){return "56"}}'à la liste. Les résultats mitigés sont intéressants.
murrayju
3
Donc, le résumé du tableau est que +c'est juste une façon d'écrire plus courte Number, et les plus éloignées sont juste des façons folles de le faire qui échouent sur les cas extrêmes?
Mihail Malostanidis
Est-ce que [] .undef est une chose, ou est-ce juste une manière arbitraire de générer undef? Impossible de trouver un enregistrement de "undef" lié à JS via Google.
jcairney
10

Je pense que le tableau de la réponse de thg435 est complet, mais nous pouvons le résumer avec les modèles suivants:

  • Unary plus ne traite pas toutes les fausses valeurs de la même manière, mais elles sont toutes fausses.
  • Unaire plus envoie trueà 1, mais "true"à NaN.
  • En revanche, parseIntest plus libéral pour les chaînes qui ne sont pas de purs chiffres. parseInt('123abc') === 123, tandis que les +rapports NaN.
  • Numberacceptera des nombres décimaux valides, alors parseIntque tout simplement abandonne tout au-delà de la décimale. Ainsi parseIntimite le comportement C, mais n'est peut-être pas idéal pour évaluer les entrées de l'utilisateur.
  • Les deux coupent les espaces dans les chaînes.
  • parseInt, étant un analyseur mal conçu , accepte les entrées octales et hexadécimales. Unary plus ne prend que hexadécimal.

Les valeurs fausses sont converties en Numbersuivant ce qui aurait du sens dans C: nullet falsesont toutes les deux nulles. ""aller à 0 ne suit pas tout à fait cette convention mais me semble assez logique.

Par conséquent, je pense que si vous validez l'entrée de l'utilisateur, unary plus a un comportement correct pour tout sauf qu'il accepte les décimales (mais dans mes cas réels, je suis plus intéressé par la capture de l'entrée d'e-mail au lieu de userId, valeur entièrement omise, etc.), alors que parseInt est trop libéral.

Djechlin
la source
2
"Unaire plus ne prend que de l'hexadécimal" Vous ne voulez pas dire décimal?
krillgar
0

Attention, parseInt est plus rapide que l'opérateur unaire + dans Node.JS, il est faux que + ou | 0 sont plus rapides, ils ne le sont que pour les éléments NaN.

Regarde ça:

var arg=process.argv[2];

rpt=20000;
mrc=1000;

a=[];
b=1024*1024*1024*1024;
for (var i=0;i<rpt;i++)
 a[i]=Math.floor(Math.random()*b)+' ';

t0=Date.now();
if ((arg==1)||(arg===undefined))
 for (var j=0;j<mrc;j++) for (var i=0;i<rpt;i++) {
  c=a[i]-0;
 }
t1=Date.now();
if ((arg==2)||(arg===undefined)) {
 for (var j=0;j<mrc;j++) for (var i=0;i<rpt;i++) {
  d=a[i]|0;
 }
}
t2=Date.now();
if ((arg==3)||(arg===undefined)) {
 for (var j=0;j<mrc;j++) for (var i=0;i<rpt;i++) {
  e=parseInt(a[i]);
 }
}
t3=Date.now();
 if ((arg==3)||(arg===undefined)) {
 for (var j=0;j<mrc;j++) for (var i=0;i<rpt;i++) {
  f=+a[i];
 }
}
t4=Date.now();

console.log(a[i-1],c,d,e,f);
console.log('Eseguiti: '+rpt*mrc+' cicli');
console.log('parseInt '+(t3-t2));
console.log('|0 '+(t2-t1));
console.log('-0 '+(t1-t0));
console.log('+ '+(t4-t3));
Informate.it
la source
-3

Pensez également aux performances . J'ai été surpris que cela parseIntbat unaire plus sur iOS :) Ceci n'est utile que pour les applications Web avec une forte consommation de processeur. En règle générale, je suggérerais à JS opt-guys de considérer n'importe quel opérateur JS plutôt qu'un autre du point de vue des performances mobiles de nos jours.

Alors, passez d'abord au mobile ;)

Arman McHitarian
la source
Comme les autres messages l'expliquent, ils font des choses assez différentes, donc vous ne pouvez pas facilement échanger l'un pour l'autre…
Bergi
@Bergi, d'accord, mais ils ont aussi beaucoup en commun. Dites-moi juste une solution de performance en JavaScript qui est certainement le seul bon choix? En général, c'est pourquoi les règles empiriques sont là pour nous. Le reste est spécifique à une tâche.
Arman McHitarian
3
@ArmanMcHitaryan c'est une microoptimisation inutile et ça n'en vaut pas la peine. Consultez cet article - fabien.potencier.org/article/8/…
webvitaly
@webvitaly, bel article. Il y a toujours des gars très orientés vers la performance qui aiment juste écrire du code "le plus rapide possible" et dans certains projets spécifiques, ce n'est pas mal. C'est pourquoi j'ai mentionné "JS opt-guys to consider". ce n'est pas un must bien sûr :), mais je le trouve moi-même beaucoup plus lisible en plus.
Arman McHitarian
Avez-vous une citation pour cela? Votre lien est rompu.
djechlin