parseInt vs unry plus, коли використовувати?


149

Які відмінності між цим рядком:

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

і ця лінія

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

Цей тест jsperf показує, що оператор Ury набагато швидший у поточній хромованій версії, якщо припустити, що це для node.js !?

Якщо я спробую перетворити рядки, які не є числами, обидва повертаються NaN:

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

Тож коли я вважаю за краще використовувати parseIntнад унарним плюсом (особливо в node.js) ???

edit : а яка різниця для оператора подвійного тильду ~~?


Відповіді:


169

Будь ласка, дивіться цю відповідь для більш повного набору справ




Ну ось декілька відмінностей, про які я знаю:

  • Порожній рядок ""оцінюється до а 0, тоді як parseIntоцінює його NaN. IMO, порожнім рядком має бути а 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розглядаються як нечислові компоненти (по крайней мере , на base10).

    Одинар +перетворить їх належним чином.

    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
Також при використанні радіусу+"0xf" != parseInt("0xf", 10)
Алекс К.

мені найбільше подобається ваша відповідь досі, чи можете ви також пояснити, у чому різниця для оператора подвійного тильду ~~?
hereandnow78

@ 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

Кінцева таблиця переходів незалежно від кількості: Таблиця переходів


2
Будь ласка, додайте "NaN"до цієї таблиці.
chharvey

Можливо, варто додати isNaNстовпчик до цієї таблиці: наприклад, isNaN("")false (тобто це вважається числом), але parseFloat("")є NaN, що може бути gotcha, якщо ви намагаєтесь isNaNперевірити вхід, перш ніж передавати його вparseFloat
Retsam

Ви також повинні додати '{valueOf: function(){return 42}, toString: function(){return "56"}}'до списку. Змішані результати цікаві.
murrayju

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, цілком опущеному значенні тощо), тоді як розбір занадто ліберальний.


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

-3

Розгляньте і ефективність . Мене здивувало, що parseIntна iOS перемагає одиничний плюс :) Це корисно лише для веб-додатків із великим споживанням процесора. Як правило, я пропоную JS-оптимісти розглянути будь-якого оператора JS над іншим з точки зору продуктивності мобільних пристроїв.

Отже, перейдіть по -перше ;)


Як пояснюють інші пости, вони роблять зовсім інші речі, тому ви не можете легко поміняти одне на інше…
Bergi

@Bergi, правда, але вони також мають багато спільного. Скажіть мені лише одне рішення про продуктивність у JavaScript, яке, безумовно, є єдиним правильним вибором? Взагалі, ось чому для нас є великі пальці. Решта - це завдання.
Арман Макгітарін

3
@ArmanMcHitaryan це марна мікрооптимізація, і цього не варто. Перегляньте цю статтю - fabien.potencier.org/article/8/…
webvitaly

@webvitaly, приємна стаття. Завжди завжди є дуже орієнтовані на парфу хлопці, які просто люблять писати «найшвидший можливий» код і в деяких конкретних проектах, що непогано. Тому я згадав "JS opt-guys щоб розглянути". це НЕ ОБОВ'ЯЗКОВО звичайно :), але я сам вважаю це набагато більш читабельним.
Арман Макгітарін

У вас є цитування на це? Ваше посилання розірвано.
дічлін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.