parseInt vs унарный плюс, когда использовать который?

149

Каковы различия между этой линией:

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

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

hereandnow78
источник

Ответы:

169

Пожалуйста, смотрите этот ответ для более полного набора случаев




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

  • Пустая строка ""оценивается как a 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's correct.
    
    parseInt("0xf", 10) === 0; //true. This is supposed to be 15
    +'0xf' === 15;             //true. This one's correct.
Джозеф
источник
6
Также при использовании radix+"0xf" != parseInt("0xf", 10)
Alex K.
Мне больше всего нравится ваш ответ, вы также можете объяснить, в чем разница с оператором двойной тильды ~~?
сейчас78
@ hereandnow78 Это будет объяснено здесь . Это битовый эквивалент Math.floor(), который в основном отсекает десятичную часть.
Джозеф
4
На самом деле, "2e3"не является допустимым целочисленным представлением для 2000. Это действительное число с плавающей запятой, хотя: parseFloat("2e3")будет правильно давать 2000в качестве ответа. И "0xf"требует по крайней мере основания 16, поэтому parseInt("0xf", 10)возвращает 0, тогда как parseInt("0xf", 16)возвращает значение 15, которое вы ожидали.
Барт
2
@ Joseph the Dreamer и @ hereandnow78: Двойная тильда обрезает десятичную часть числа, в то время как Math.floor возвращает ближайший нижний номер. Они работают одинаково для положительного числа, но Math.floor(-3.5) == -4и ~~-3.5 == -3.
Альбин
261

Конечная таблица преобразования числа в число: Таблица перевода

georg
источник
2
Пожалуйста, добавьте "NaN"к этой таблице.
Чарви
Возможно, стоит добавить isNaNстолбец в эту таблицу: например, isNaN("")false (т. Е. Он считается числом), но parseFloat("")это NaNможет быть ошибкой, если вы пытаетесь использовать isNaNдля проверки ввода перед его передачейparseFloat
Retsam
Вы также должны добавить '{valueOf: function(){return 42}, toString: function(){return "56"}}'в список. Смешанные результаты интересны.
Мюррайю
3
Итак, краткое изложение таблицы - это +просто более короткий способ написания Number, а дальнейшие - просто сумасшедшие способы сделать это, которые терпят неудачу в крайних случаях?
Михаил Малостанидис
Является ли [] .undef чем-то, или это просто произвольный способ генерирования неопределенного? Не удалось найти ни одной записи "undef", связанной с JS, через Google.
jcairney
10

Я полагаю, что таблица в ответе thg435 является исчерпывающей, но мы можем подвести итог следующим шаблонам:

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

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

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

djechlin
источник
2
«Унарный плюс принимает только шестнадцатеричное» Разве вы не имеете в виду десятичное?
крильгар
0

Будьте осторожны, parseInt быстрее, чем + унарный оператор в Node.JS, неверно, что + или | 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));
Informate.it
источник
-3

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

Итак, иди мобильным первым ;)

Арман Макхитариан
источник
Как объясняют другие посты, они делают совершенно разные вещи, поэтому вы не можете легко поменять одно на другое…
Берги
@ Берги, верно, но у них тоже много общего. Скажите мне только одно решение для повышения производительности в JavaScript, которое определенно является единственным правильным выбором? В общем, вот почему правило для нас там. Остальное зависит от конкретной задачи.
Арман Макхитариан,
3
@ArmanMcHitaryan - это бесполезная микрооптимизация, и она того не стоит. Проверьте эту статью - fabien.potencier.org/article/8/…
webvitaly
@webvitaly, хорошая статья. Всегда есть очень ориентированные на перфект ребята, которые просто любят писать «максимально быстрый» код, и в некоторых конкретных проектах это неплохо. Вот почему я упомянул «JS opt-парни, чтобы рассмотреть». это, конечно, НЕ ДОЛЖНО :), но я сам нахожу это гораздо более читабельным.
Арман Макхитариан
У вас есть цитата для этого? Ваша ссылка не работает.
Джечлин