ParseInt против унарного плюса - когда использовать

В чем разница между этой строкой:

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

и эта строка

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

Этот тест jsperf показывает, что унарный оператор намного быстрее в текущей версии chrome, предполагая, что это для node.js!?

Если я пытаюсь преобразовать строки, которые не являются номерами, возвращают NaN:

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

Итак, когда я должен использовать parseInt над унарным плюсом (особенно в node.js)???

изменить: и какая разница с оператором двойной тильды ~~?

Ответ 1

См. этот ответ для более полного набора случаев




Ну, вот несколько отличий, о которых я знаю:

  • Пустая строка "" оценивается как 0, а parseInt оценивает ее на NaN. ИМО, пустая строка должна быть NaN.

    +'' === 0;              //true
    isNaN(parseInt('',10)); //true
    
  • Унарный + действует больше как parseFloat, так как он также принимает десятичные числа.

    parseInt, с другой стороны, останавливает синтаксический анализ, когда видит нечисловой символ, например период, который должен быть десятичной точкой ..

    +'2.3' === 2.3;           //true
    parseInt('2.3',10) === 2; //true
    
  • parseInt и parseFloat анализирует и строит строку слева направо. Если они видят недопустимый символ, он возвращает то, что было проанализировано (если есть), как число, и NaN, если ни один не был проанализирован как число.

    Унарный +, с другой стороны, вернет NaN, если вся строка неконвертируется в число.

    parseInt('2a',10) === 2; //true
    parseFloat('2a') === 2;  //true
    isNan(+'2a');            //true
    
  • Как видно из комментария @Alex K., parseInt и parseFloat будут разбираться по символу. Это означает, что шестнадцатеричные и экспоненциальные обозначения потерпят неудачу, так как x и e рассматриваются как нечисловые компоненты (по крайней мере, на основе 10).

    Унарный + будет правильно преобразовывать их.

    parseInt('2e3',10) === 2;  //true. This is supposed to be 2000
    +'2e3' === 2000;           //true. This one correct.
    
    parseInt("0xf", 10) === 0; //true. This is supposed to be 15
    +'0xf' === 15;             //true. This one correct.
    

Ответ 2

Конечная таблица преобразования любых чисел в число: введите описание изображения здесь

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

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"',

    'null',
    '[].undef',
    '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 Number.isNaN(n) ? wrap('b', n) : String(n);
}

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

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 }

Ответ 3

Таблица в ответе thg435, я считаю, всеобъемлющей, однако мы можем обобщить следующие шаблоны:

  • Унарный плюс не относится ко всем значениям ложности одинаково, но все они оказываются ложными.
  • Унарный плюс отправляет true в 1, а "true" - NaN.
  • С другой стороны, parseInt является более либеральным для строк, которые не являются чистыми цифрами. parseInt('123abc') === 123, тогда как + сообщает NaN.
  • Number будет принимать действительные десятичные числа, тогда как parseInt просто выпадает все за десятичным. Таким образом, parseInt имитирует поведение C, но, пожалуй, не идеально подходит для оценки ввода пользователя.
  • Оба обрезают пробелы в строках.
  • parseInt, будучи плохо спроектированным парсером, принимает восьмеричный и шестнадцатеричный ввод. Унарный плюс используется только в шестимерном порядке.

Значения Falsy преобразуются в Number после того, что имеет смысл в C: null и false равны нулю. "" Переход к 0 не совсем соответствует этому соглашению, но имеет для меня достаточный смысл.

Поэтому я думаю, что если вы проверяете ввод пользователя, унарный плюс имеет правильное поведение для всего, кроме того, что он принимает десятичные числа (но в моих реальных случаях я больше заинтересован в том, чтобы поймать ввод электронной почты вместо userId, значение опущено полностью и т.д.), тогда как parseInt слишком либеральный.

Ответ 4

Будьте осторожны, parseInt быстрее, чем + унарный оператор в Node.JS, это false, что + или | 0 быстрее, они быстрее только для элементов NaN.

Проверьте это:

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));

Ответ 5

Рассмотрим производительность. Я был удивлен, что parseInt бьет унарный плюс на iOS:) Это полезно для веб-приложений с большим потреблением процессора. Как правило, я предлагаю JS opt-guys рассматривать любой JS-оператор над другим с точки зрения производительности мобильных устройств в настоящее время.

Итак, перейдите mobile-first;)