javascript - parseInt vs plus unar, când să folosești care?


Care sunt diferențele dintre această linie:

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

și această linie

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

Acest test jsperf arată că operatorul unar este mult mai rapid în versiunea actuală de Chrome, presupunând că este pentru node.js!?

Dacă încerc să convertesc șiruri care nu sunt numere, ambele returnează NaN:

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

Deci când ar trebui să prefer folosirea parseInt în locul semnului plus unar (în special în node.js)???

editare: și care este diferența față de operatorul dublu tilde ~~?

Răspuns #1

Tabelul final de conversie orice-la-număr:

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 }

Răspunsul #2

Ei bine, iată câteva diferențe pe care le cunosc:

  • Un șir gol "" se evaluează ca 0, în timp ce parseInt îl evaluează ca NaN. În opinia mea, un șir gol ar trebui să fie NaN.

      +'' === 0;              //true
      isNaN(parseInt('',10)); //true
    
  • Operatorul unar + se comportă mai mult ca parseFloat, deoarece acceptă și zecimale.

    parseInt, pe de altă parte, se oprește din analizare atunci când întâlnește un caracter nenumeric, cum ar fi punctul care este menit să fie un punct zecimal ..

      +'2.3' === 2.3;           //true
      parseInt('2.3',10) === 2; //true
    
  • parseInt și parseFloat analizează și construiesc șirul de caractere de la stânga la dreapta. Dacă întâlnesc un caracter nevalid, returnează ceea ce a fost analizat (dacă există) ca număr și NaN dacă nu a fost analizat niciun număr.

    Operatorul unar +, pe de altă parte, va returna NaN dacă întregul șir nu poate fi convertit într-un număr.

      parseInt('2a',10) === 2; //true
      parseFloat('2a') === 2;  //true
      isNaN(+'2a');            //true
    
  • După cum se vede în comentariul lui @Alex K., parseInt și parseFloat vor analiza caracterele. Aceasta înseamnă că notațiile hex și exponentiale vor eșua deoarece x și e sunt tratate ca componente nenumerice (cel puțin în baza 10).

    Operatorul unar + îi va converti totuși corect.

      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.
    

Răspunsul #3

Tabelul din răspunsul lui thg435 cred că este cuprinzător, totuși putem rezuma cu următoarele tipare:

  • Operatorul unar plus nu tratează toate valorile false în același mod, dar toate ies ca false.
  • Operatorul unar plus transformă true în 1, dar "true" în NaN.
  • Pe de altă parte, parseInt este mai liberal pentru șiruri care nu sunt doar cifre. parseInt('123abc') === 123, în timp ce + raportează NaN.
  • Number va accepta numere zecimale valide, în timp ce parseInt pur și simplu ignoră tot ce urmează după virgulă. Astfel, parseInt imită comportamentul din C, dar poate nu este ideal pentru evaluarea inputului utilizatorului.
  • Ambele elimină spațiile albe din șiruri.
  • parseInt, fiind un parser prost conceput, acceptă input octal și hexadecimal. Plusul unar ia doar hexadecimal.

Valorile false se convertesc la Number urmând ceea ce ar avea sens în C: null și false sunt ambele zero. "" devenind 0 nu urmează tocmai această convenție, dar are suficient sens pentru mine.

Prin urmare, cred că dacă validați inputul utilizatorului, operatorul unar plus are un comportament corect pentru tot, cu excepția faptului că acceptă zecimale (dar în cazurile mele reale sunt mai interesat să detectez inputul de tip email în loc de userId, valoarea omisă complet, etc.), în timp ce parseInt este prea liberal.