193 votes

parseInt vs unary plus, quand utiliser lequel ?

Quelles sont les différences entre cette ligne :

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

et cette ligne

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

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

Si j'essaie de convertir des chaînes de caractères qui ne sont pas des nombres, les deux retours sont les suivants NaN :

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

Alors quand dois-je préférer utiliser parseInt sur le plus unaire (surtout dans node.js) ? ???

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

3 votes

0 votes

@RokoC.Buljan Le service semble mort. Une mise à jour ?

368voto

georg Points 52691

Le tableau ultime de conversion de n'importe quoi en chiffres : Conversion table

EXPRS = [
    'parseInt(x)',
    'parseFloat(x)',
    'Number(x)',
    '+x',
    '~~x',
    'x>>>0',
    'isNaN(x)'

];

VALUES = [
    '"123"',
    '"+123"',
    '"-123"',
    '"123.45"',
    '"-123.45"',
    '"12e5"',
    '"12e-5"',

    '"0123"',
    '"0000123"',
    '"0b111"',
    '"0o10"',
    '"0xBABE"',

    '"4294967295"',
    '"123456789012345678"',
    '"12e999"',

    '""',
    '"123foo"',
    '"123.45foo"',
    '"  123   "',
    '"foo"',
    '"12e"',
    '"0b567"',
    '"0o999"',
    '"0xFUZZ"',

    '"+0"',
    '"-0"',
    '"Infinity"',
    '"+Infinity"',
    '"-Infinity"',
    'BigInt(1)',

    'null',
    'undefined',
    'true',
    'false',
    'Infinity',
    'NaN',

    '{}',
    '{valueOf: function(){return 42}}',
    '{toString: function(){return "56"}}',

];

//////

function wrap(tag, s) {
    if (s && s.join)
        s = s.join('');
    return '<' + tag + '>' + String(s) + '</' + tag + '>';
}

function table(head, rows) {
    return wrap('table', [
        wrap('thead', tr(head)),
        wrap('tbody', rows.map(tr))
    ]);
}

function tr(row) {
    return wrap('tr', row.map(function (s) {
        return wrap('td', s)
    }));
}

function val(n) {
    return n === true || Number.isNaN(n) || n === "Error" ? wrap('b', n) : String(n);
}

var rows = VALUES.map(function (v) {
    var x = eval('(' + v + ')');
    return [v].concat(EXPRS.map(function (e) {
        try {
            return val(eval(e));
        } catch {
            return val("Error");
        }
    }));
});

document.body.innerHTML = table(["x"].concat(EXPRS), rows);

table { border-collapse: collapse }
tr:nth-child(odd) { background: #fafafa }
td { border: 1px solid #e0e0e0; padding: 5px; font: 12px monospace }
td:not(:first-child) { text-align: right }
thead td { background: #3663AE; color: white }
b { color: red }

4 votes

Veuillez ajouter "NaN" à cette table.

2 votes

Il peut être intéressant d'ajouter un isNaN à ce tableau : par exemple, isNaN("") est faux (c'est-à-dire qu'il est considéré comme un nombre), mais parseFloat("") es NaN ce qui peut être un piège, si vous essayez d'utiliser isNaN pour valider l'entrée avant de la transmettre à parseFloat

2 votes

Vous devez également ajouter '{valueOf: function(){return 42}, toString: function(){return "56"}}' à la liste. Les résultats mitigés sont intéressants.

209voto

Joseph the Dreamer Points 43727

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

  • Une chaîne vide "" est évalué à un 0 alors que parseInt l'évalue à NaN . IMO, une chaîne vide devrait être un NaN .

      +'' === 0;              //true
      isNaN(parseInt('',10)); //true
  • L'unaire + agit plutôt comme parseFloat puisqu'il accepte également les décimales.

    parseInt d'autre part, arrête l'analyse lorsqu'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
  • parseInt y parseFloat analyse et construit la chaîne de caractères de gauche à droite . S'il voit un caractère invalide, il renvoie ce qui a été analysé (le cas échéant) sous la forme d'un nombre, et NaN si aucun n'a été analysé comme un nombre.

    L'unaire + d'autre part, retournera NaN si la chaîne entière n'est pas convertible en un nombre.

      parseInt('2a',10) === 2; //true
      parseFloat('2a') === 2;  //true
      isNaN(+'2a');            //true
  • Comme on peut le voir dans le commentaire de @Alex K. , parseInt y parseFloat analysera par caractère. Cela signifie que les notations en hexadécimal et en exposant échoueront puisque l'option x y e sont traitées comme des composantes non numériques (au moins en base 10).

    L'unaire + les convertira cependant 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.

6 votes

De même, lorsqu'on utilise un radix +"0xf" != parseInt("0xf", 10)

0 votes

J'aime beaucoup votre réponse jusqu'à présent, pouvez-vous également expliquer quelle est la différence avec l'opérateur double tilde ~~ ?

0 votes

@hereandnow78 Ce serait expliqué ici . C'est l'équivalent bit à bit de Math.floor() qui supprime essentiellement la partie décimale.

11voto

djechlin Points 18051

Le tableau figurant dans la réponse de thg435 est, je crois, complet, mais nous pouvons résumer avec les modèles suivants :

  • Unary plus ne traite pas toutes les valeurs faussées de la même manière, mais elles sortent toutes faussées.
  • Unaire plus envoie true à 1, mais "true" a NaN .
  • D'un autre côté, parseInt est plus libérale pour les chaînes de caractères qui ne sont pas des chiffres purs. parseInt('123abc') === 123 alors que + rapports NaN .
  • Number acceptera les nombres décimaux valides, tandis que parseInt ne fait que laisser tomber tout ce qui dépasse la décimale. Ainsi parseInt imite le comportement de C, mais n'est peut-être pas idéal pour évaluer l'entrée de l'utilisateur.
  • Tous deux coupent les espaces dans les chaînes de caractères.
  • parseInt qui est une mauvaise conception analyseur syntaxique accepte les entrées octales et hexadécimales. Unary plus ne prend que l'hexadécimal.

Les valeurs Falsy sont converties en Number en suivant ce qui aurait un sens en C : null y false sont toutes deux nulles. "" qui va à 0 ne suit pas tout à fait cette convention mais a suffisamment de sens pour moi.

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é à attraper l'entrée de l'email au lieu de userId, la valeur omise entièrement, etc), alors que parseInt est trop libéral.

4 votes

"Unary plus ne prend que l'hexadécimal" Ne voulez-vous pas dire décimal ?

1voto

Informate.it Points 81

Attention, parseInt est plus rapide que l'opérateur unaire + dans Node.JS, il est faux que + ou |0 soient 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));

1voto

user3446605 Points 29

Je recommande d'utiliser Math.floor (ou ~~ si vous savez que les nombres sont positifs) au lieu de parseString. +(expression) est hors de portée, car +(expression) est plus proche de parseFloat. Regardez ce petit benchmark :

// 1000000 iterations each one
node test_speed
Testing ~~, time: 5 ms
Testing parseInt with number, time: 25 ms
Testing parseInt with string, time: 386 ms
Testing Math.floor, time: 18 ms

Le code source du benchmark :

/* el propósito de este script es evaluar
que expresiones se ejecutan más rápido para así 
decidir cuál usar */

main()
async function main(){
    let time, x 
    let number = 23456.23457

    let test1 = ()=>{
        x = 0
        time = Date.now() 
        for(let i=0;i<1000000;i++){
            let op = Math.floor(number / 3600)
            x = op
        }
        console.info("Testing Math.floor, time:", Date.now() - time, "ms")
    }

    let test2 = ()=>{
        x = 0
        time = Date.now() 
        for(let i=0;i<1000000;i++){
            let op = parseInt(number / 3600)
            x = op
        }
        console.info("Testing parseInt with number, time:", Date.now() - time, "ms")
    }

    let test3 = ()=>{
        x = 0
        time = Date.now() 
        for(let i=0;i<1000000;i++){
            let op = parseInt((number / 3600).toString())
            x = op
        }
        console.info("Testing parseInt with string, time:", Date.now() - time, "ms")
    }

    let test4 = ()=>{
        x = 0
        time = Date.now() 
        for(let i=0;i<1000000;i++){
            let op = ~~(number / 3600)
            x = op
        }
        console.info("Testing ~~, time:", Date.now() - time, "ms")
    }

    test4()
    test2()
    test3()
    test1()

}

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