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)???
редактировать: и в чем разница с оператором двойной тильды ~~
?
6 ответов
Пожалуйста, смотрите этот ответ для более полного набора случаев
Ну, вот несколько отличий, о которых я знаю:
Пустая строка
""
оценивает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.
Конечная таблица преобразования числа в число:
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"',
'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 n === true || 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 }
Я полагаю, что таблица в ответе thg435 является исчерпывающей, но мы можем подвести итог следующим шаблонам:
- Унарный плюс не относится ко всем ложным значениям одинаково, но все они оказываются ложными.
- Унарный плюс отправляет
true
до 1, но"true"
вNaN
, - С другой стороны,
parseInt
является более либеральным для строк, которые не являются чистыми цифрами.parseInt('123abc') === 123
, в то время как+
отчетыNaN
, Number
будет принимать действительные десятичные числа, тогда какparseInt
просто отбрасывает все после десятичного числа. таким образомparseInt
имитирует поведение C, но, возможно, не идеально подходит для оценки пользовательского ввода.- Оба обрезают пробелы в строках.
parseInt
, будучи плохо спроектированным парсером, принимает восьмеричный и шестнадцатеричный ввод. Унарный плюс принимает только шестнадцатеричный.
Ложные значения конвертируются в Number
после того, что будет иметь смысл в C: null
а также false
оба равны нулю. ""
переход к 0 не совсем соответствует этому соглашению, но имеет для меня достаточно смысла.
Поэтому я думаю, что если вы проверяете пользовательский ввод, унарный плюс имеет правильное поведение для всего, кроме того, что он принимает десятичные дроби (но в моих реальных случаях меня больше интересует перехват ввода электронной почты вместо userId, значение опускается полностью и т. Д.), Тогда как parseInt слишком либерален.
Будьте осторожны, 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));
Я рекомендую использовать Math.floor (или ~~, если вы знаете, что числа положительные) вместо parseString. +(выражение) выходит за рамки, потому что +(выражение) больше похоже на parseFloat. Посмотрите этот небольшой тест:
// 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
Исходный код теста:
/* 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()
}
Учитывайте производительность тоже. Я был удивлен, что parseInt
превосходит унарный плюс на iOS:) Это полезно для веб-приложений только с высокой загрузкой процессора. В качестве практического правила я бы предложил JS opt-guys рассматривать любого оператора JS вместо другого с точки зрения производительности мобильных устройств в настоящее время.
Итак, иди мобильным первым;)