parseInt - unary plus, hangisi ne zaman kullanılır?


160

Bu satır arasındaki farklar nelerdir:

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

ve bu çizgi

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

Bu jsperf testi , node.js için olduğu varsayılarak, tekli operatörün mevcut krom sürümünde çok daha hızlı olduğunu gösterir !?

Sayı olmayan dizeleri dönüştürmeye çalışırsam, her ikisi de şunu döndürür NaN:

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

Öyleyse ne zaman parseInttekli artı kullanmayı tercih etmeliyim (özellikle node.js'de) ???

düzenleme : ve çift tilde operatöründen farkı ~~nedir?


Yanıtlar:


179

# Daha eksiksiz bir vaka kümesi için lütfen bu yanıta bakın




İşte bildiğim birkaç farklılık:

  • Boş bir dize "", a olarak değerlendirilirken 0, olarak parseIntdeğerlendirilir NaN. IMO, boş bir dize bir NaN.

      +'' === 0;              //true
      isNaN(parseInt('',10)); //true
    
  • Tekli , ondalık sayıları da kabul ettiği için +daha çok davranır parseFloat.

    parseIntÖte yandan, ondalık nokta olması amaçlanan nokta gibi sayısal olmayan bir karakter gördüğünde ayrıştırmayı durdurur ..

      +'2.3' === 2.3;           //true
      parseInt('2.3',10) === 2; //true
    
  • parseIntve parseFloatdizeyi soldan sağa ayrıştırır ve oluşturur . Geçersiz bir karakter görürlerse, ayrıştırılmış olanı (varsa) sayı olarak ve NaNhiçbiri sayı olarak çözümlenmemişse döndürür .

    +Öte yandan tekli , NaNdizenin tamamı bir sayıya dönüştürülemiyorsa geri dönecektir .

      parseInt('2a',10) === 2; //true
      parseFloat('2a') === 2;  //true
      isNaN(+'2a');            //true
    
  • As yorumda görülen @Alex K. , parseIntve parseFloatkarakteriyle ayrıştırmak edecektir. Bu, onaltılı ve üslü gösterimlerin başarısız olacağı anlamına gelir, çünkü xve esayısal olmayan bileşenler olarak değerlendirilir (en azından baz10'da).

    Tekli +onları doğru bir şekilde dönüştürecektir.

      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
Ayrıca bir sayı tabanı kullanırken+"0xf" != parseInt("0xf", 10)
Alex K.

Şimdiye kadar cevabınızı çok beğendim, çift tilde işleciyle ~~ arasındaki farkın ne olduğunu da açıklayabilir misiniz?
hereandnow78

@ hereandnow78 Bu burada açıklanacaktır . Math.floor()Temelde ondalık kısmı kesen bitsel eşdeğeridir .
Joseph

4
Aslında, "2e3"için geçerli bir tamsayı temsili değildir 2000. Yine de geçerli bir kayan nokta sayısıdır: cevap olarak parseFloat("2e3")doğru bir şekilde verilecektir 2000. Ve "0xf"en az 16 tabanını gerektirir, bu yüzden parseInt("0xf", 10)geri döner 0, parseInt("0xf", 16)beklediğiniz 15 değerini döndürür.
Bart

2
@Joseph the Dreamer ve @ hereandnow78: Çift tilde sayının ondalık kısmını keserken Math.floor en yakın küçük sayıyı döndürür. Pozitif sayı için aynı şekilde çalışırlar, ama Math.floor(-3.5) == -4ve ~~-3.5 == -3.
Albin

278

Nihai sayıdan sayıya dönüştürme tablosu: Dönüşüm tablosu


3
Lütfen "NaN"bu tabloya ekleyin .
chharvey

1
Bir ekleme değer olabilir isNaNbu tabloya sütun: örneğin, isNaN("")(yani bu bir numara olarak kabul edilir) yanlış olmakla parseFloat("")olduğunu NaNkullanmak çalışıyorsanız, bir gotcha olabilen, isNaNgeçirmeden önce giriş doğrulamak içinparseFloat
Retsam

1
Ayrıca '{valueOf: function(){return 42}, toString: function(){return "56"}}'listeye eklemelisiniz . Karışık sonuçlar ilginç.
murrayju

4
Öyleyse, tablonun özeti, bu +sadece daha kısa bir yazma yolu ve daha ileri Numberolanlar, uç durumlarda başarısız olan bunu yapmanın çılgın yolları mı?
Mihail Malostanidis

[] .Undef bir şey mi, yoksa bu sadece tanımsız üretmenin keyfi bir yolu mu? Google üzerinden JS ile ilgili herhangi bir "undef" kaydı bulunamıyor.
jcairney

10

Thg435'in cevabındaki tablonun kapsamlı olduğuna inanıyorum, ancak aşağıdaki kalıplarla özetleyebiliriz:

  • Unary plus, tüm yanlış değerlere aynı şekilde davranmaz, ancak hepsi yanlış çıkar.
  • Birli artı gönderir true1'e ama "true"hiç NaN.
  • Öte yandan, parseIntsalt rakam olmayan dizeler için daha liberaldir. parseInt('123abc') === 123, oysa +raporlar NaN.
  • Numbergeçerli ondalık sayıları kabul ederken, parseIntyalnızca ondalık sayıları aşan her şeyi bırakır. Bu nedenle parseIntC davranışını taklit eder, ancak kullanıcı girdisini değerlendirmek için belki de ideal değildir.
  • Her ikisi de dizelerdeki boşlukları keser.
  • parseIntkötü tasarlanmış bir ayrıştırıcı olduğundan sekizlik ve onaltılık girdileri kabul eder. Tekli artı yalnızca onaltılı alır.

Yanlış değerler Number, C: ' de mantıklı olan aşağıdakilere dönüşür nullve falseher ikisi de sıfırdır. ""0'a gitmek bu düzene tam olarak uymuyor ama bana yeterince mantıklı geliyor.

Bu nedenle, kullanıcı girdisini doğruluyorsanız, unary plus'ın ondalık sayıları kabul etmesi dışında her şey için doğru davranışa sahip olduğunu düşünüyorum (ancak gerçek hayattaki durumumda, userId yerine e-posta girdisini yakalamakla daha çok ilgileniyorum, değer tamamen atlandı vb.) parseInt çok liberal.


4
"Tekli artı yalnızca onaltılık alır" Ondalık demek istemiyor musunuz?
krillgar

0

Dikkatli olun, node.JS'de parseInt + tekli operatörden daha hızlıdır, + veya | 0'ın daha hızlı olduğu yanlıştır, yalnızca NaN öğeleri için daha hızlıdır.

Şuna bir bak:

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

-2

Performansı da düşünün . Şaşırmıştım kiparseIntİOS'ta unary plus'ı geçmesi :) Bu, yalnızca yoğun CPU tüketimi olan web uygulamaları için yararlıdır. Genel bir kural olarak, JS'yi tercih edenlerin günümüzde mobil performans açısından herhangi bir JS operatörünü başka bir operatör yerine değerlendirmelerini öneririm.

Öyleyse, mobil cihazlara öncelik verin ;)


Diğer gönderiler oldukça farklı şeyler yaptıklarını açıkladığından, birini
diğeriyle

@Bergi, doğru, ama aynı zamanda pek çok ortak yönleri de var. Bana JavaScript'te kesinlikle tek doğru seçim olan tek bir performans çözümünü söyleyin? Genel olarak bu yüzden, bizim için başparmak kuralı var. Gerisi göreve özeldir.
Arman McHitarian

3
@ArmanMcHitaryan, bu işe yaramaz mikrooptimizasyondur ve buna değmez. Bu makaleye göz atın - fabien.potencier.org/article/8/…
webvitaly

@webvitaly, güzel makale. Dışarıda her zaman "mümkün olan en hızlı" kodu yazmayı seven ve bazı özel projelerde bu hiç de fena olmayan, mükemmel odaklı insanlar vardır. Bu yüzden "JS opt-guys to think" den bahsettim. elbette bu BİR ZORUNLULUK DEĞİL :), ama ben kendime ek olarak çok daha okunaklı buluyorum.
Arman McHitarian

Bunun için bir alıntı var mı? Bağlantınız koptu.
djechlin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.