parseInt vs 一元加,什么时候使用哪个?

IT技术 javascript node.js
2021-01-31 06:09:26

这行有什么区别:

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个回答

最终的任意数字转换表: 换算表

[].undef 是一个东西,还是只是一种生成 undefined 的任意方式?通过谷歌找不到任何与JS相关的“undef”记录。
2021-03-14 06:09:26
请添加"NaN"到此表中。
2021-03-16 06:09:26
您还应该添加'{valueOf: function(){return 42}, toString: function(){return "56"}}'到列表中。混合的结果很有趣。
2021-03-29 06:09:26
可能值得isNaN在此表中添加一列:例如,isNaN("")is false (即它被认为是一个数字),但是parseFloat("")is NaN,这可能是一个陷阱,如果您在isNaN将输入传递给之前尝试使用它来验证输入parseFloat
2021-04-05 06:09:26
所以,表格的总结是这+只是一种较短的写作方式Number,而更进一步的只是在边缘情况下失败的疯狂方式?
2021-04-06 06:09:26

好吧,这是我所知道的一些差异:

  • 空字符串""计算为 a 0,而将其parseInt计算为NaNIMO,空白字符串应该是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.parseIntparseFloat会性格解析。这意味着十六进制和指数符号将失败,因为xe被视为非数字组件(至少在 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.
    
到目前为止我最喜欢你的回答,你能不能解释一下双波浪线运算符~~的区别是什么?
2021-03-11 06:09:26
实际上,"2e3"不是 的有效整数表示2000虽然它是一个有效的浮点数:parseFloat("2e3")将正确地2000作为答案产生。并且"0xf"至少需要以 16 为基数,这就是为什么parseInt("0xf", 10)return 0,而parseInt("0xf", 16)返回您期望的 15 值。
2021-03-17 06:09:26
同样在使用基数时 +"0xf" != parseInt("0xf", 10)
2021-03-24 06:09:26
@hereandnow78 这将在这里解释它按位等价于Math.floor(),基本上去掉了小数部分。
2021-04-04 06:09:26
@Joseph the Dreamer 和 @hereandnow78:双波浪号截断数字的小数部分,而 Math.floor 返回最接近的较低数字。它们对正数的作用相同,但是Math.floor(-3.5) == -4~~-3.5 == -3
2021-04-07 06:09:26

我认为 thg435 的答案中的表格很全面,但是我们可以总结为以下模式:

  • 一元加号不会将所有的假值都一视同仁,但它们都会出现假值。
  • 一元加号发送true到 1,但发送"true"NaN
  • 另一方面,parseInt对于非纯数字的字符串则更为宽松。 parseInt('123abc') === 123,而+报告NaN
  • Number将接受有效的十进制数,而parseInt只会删除小数点之后的所有内容。因此parseInt模仿 C 的行为,但可能不适合评估用户输入。
  • 两者都修剪字符串中的空格。
  • parseInt,作为一个设计糟糕的解析器,接受八进制和十六进制输入。一元加只取十六进制。

Falsy 值转换为Number以下在 C: 中有意义的 nullfalse并且都为零。 ""转到 0 并不完全遵循这个约定,但对我来说已经足够了。

因此,我认为如果您正在验证用户输入,除了接受小数之外,一元加号对所有内容都有正确的行为(但在我的现实生活中,我更感兴趣的是捕获电子邮件输入而不是 userId、完全省略值等),而parseInt 太自由了。

“一元加只取十六进制”你不是说十进制吗?
2021-03-22 06:09:26

我建议使用 Math.floor(或者 ~~ 如果你知道数字是正数)而不是 parseString。+(expression) 超出了范围,因为 +(expression) 更像 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()
    
}

请注意,在 Node.JS 中 parseInt 比 + 一元运算符更快,+ 或 |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));