parseInt vs unary plus, kapan harus menggunakan yang mana?

149

Apa perbedaan antara baris ini:

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

dan baris ini

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

Tes jsperf ini menunjukkan bahwa operator unary jauh lebih cepat dalam versi chrome saat ini, dengan asumsi itu untuk node.js !?

Jika saya mencoba mengonversi string yang bukan angka, keduanya kembali NaN:

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

Jadi kapan saya lebih suka menggunakan parseIntlebih dari unary plus (terutama di node.js) ???

edit : dan apa bedanya dengan operator double tilde ~~?

di sini dan sekarang78
sumber
1
Benchmark jsperf.com/parseint-vs-unary-operator
Roko C. Buljan

Jawaban:

169

Silakan lihat jawaban ini untuk satu set kasus yang lebih lengkap




Nah, inilah beberapa perbedaan yang saya ketahui:

  • String kosong ""mengevaluasi ke 0, sedangkan parseIntmengevaluasinya ke NaN. IMO, string kosong harus a NaN.

    +'' === 0;              //true
    isNaN(parseInt('',10)); //true
  • Unary +bertindak lebih seperti parseFloatkarena ia juga menerima desimal.

    parseIntdi sisi lain berhenti parsing ketika melihat karakter non-numerik, seperti periode yang dimaksudkan sebagai titik desimal ..

    +'2.3' === 2.3;           //true
    parseInt('2.3',10) === 2; //true
  • parseIntdan parseFloatmem - parsing dan membuat string dari kiri ke kanan . Jika mereka melihat karakter yang tidak valid, itu mengembalikan apa yang telah diuraikan (jika ada) sebagai angka, dan NaNjika tidak ada yang diuraikan sebagai angka.

    Unary +di sisi lain akan kembali NaNjika seluruh string tidak dapat dikonversi menjadi angka.

    parseInt('2a',10) === 2; //true
    parseFloat('2a') === 2;  //true
    isNan(+'2a');            //true
  • Seperti yang terlihat di komentar @Alex K. , parseIntdan parseFloatakan diuraikan berdasarkan karakter. Ini berarti notasi heks dan eksponen akan gagal karena xdan ediperlakukan sebagai komponen non-numerik (setidaknya pada basis10).

    Unary +akan mengubahnya dengan benar.

    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.
Joseph
sumber
6
Juga saat menggunakan radix+"0xf" != parseInt("0xf", 10)
Alex K.
Saya suka jawaban Anda sejauh ini, bisakah Anda juga menjelaskan apa bedanya dengan operator double tilde ~~?
hereandnow78
@ini dan sekarang78 Itu akan dijelaskan di sini . Ini setara bitwise Math.floor(), yang pada dasarnya memotong bagian desimal.
Joseph
4
Sebenarnya, "2e3"bukan representasi integer yang valid untuk 2000. Ini adalah angka floating point yang valid: parseFloat("2e3")akan dengan benar menghasilkan 2000sebagai jawabannya. Dan "0xf"membutuhkan setidaknya basis 16, itulah sebabnya parseInt("0xf", 10)pengembalian 0, sedangkan parseInt("0xf", 16)mengembalikan nilai 15 yang Anda harapkan.
Bart
2
@ Joseph the Dreamer dan @ hereandnow78: Double tilde memotong bagian desimal dari angka, sementara Math.floor mengembalikan angka terdekat yang lebih rendah. Mereka bekerja sama untuk angka positif, tetapi Math.floor(-3.5) == -4dan ~~-3.5 == -3.
Albin
261

Tabel konversi berapapun jumlah pamungkas: Tabel konversi

georg
sumber
2
Silakan tambahkan "NaN"ke tabel ini.
chharvey
Mungkin layak menambahkan isNaNkolom untuk tabel ini: misalnya, isNaN("")adalah palsu (yaitu itu dianggap nomor), tapi parseFloat("")adalah NaN, yang bisa menjadi gotcha, jika Anda mencoba untuk menggunakan isNaNuntuk memvalidasi input sebelum diteruskan keparseFloat
Retsam
Anda juga harus menambahkan '{valueOf: function(){return 42}, toString: function(){return "56"}}'ke daftar. Hasil campuran menarik.
murrayju
3
Jadi, ringkasan dari tabel adalah bahwa +itu hanya cara penulisan yang lebih pendek Number, dan yang lebih kasar hanyalah cara gila untuk melakukannya yang gagal pada kasus tepi?
Mihail Malostanidis
Apakah [] .adalah sesuatu, atau apakah itu hanya cara sewenang-wenang untuk menghasilkan yang tidak ditentukan? Tidak dapat menemukan catatan "undef" yang terkait dengan JS melalui Google.
jcairney
10

Tabel dalam jawaban thg435 yang saya yakini komprehensif, namun kita dapat merangkum dengan pola-pola berikut:

  • Unary plus tidak memperlakukan semua nilai falsy sama, tetapi semuanya keluar falsy.
  • Unary plus mengirim trueke 1, tetapi "true"ke NaN.
  • Di sisi lain, parseIntlebih liberal untuk string yang bukan digit murni. parseInt('123abc') === 123, sedangkan +laporan NaN.
  • Numberakan menerima angka desimal yang valid, sedangkan parseInthanya menjatuhkan semua yang melewati desimal. Dengan demikian parseIntmeniru perilaku C, tetapi mungkin tidak ideal untuk mengevaluasi input pengguna.
  • Keduanya memangkas spasi putih dalam string.
  • parseInt, sebagai pengurai yang dirancang dengan buruk , menerima input oktal dan heksadesimal. Unary plus hanya membutuhkan hexademical.

Nilai-nilai palsu dikonversi untuk Numbermengikuti apa yang masuk akal dalam C: nulldan falsekeduanya nol. ""pergi ke 0 tidak cukup mengikuti konvensi ini tetapi cukup masuk akal bagi saya.

Karena itu saya pikir jika Anda memvalidasi input pengguna, unary plus memiliki perilaku yang benar untuk semuanya kecuali menerima desimal (tetapi dalam kasus kehidupan nyata saya, saya lebih tertarik untuk menangkap input email daripada userId, nilai dihilangkan seluruhnya, dll.), Sedangkan parseInt terlalu liberal.

Djechlin
sumber
2
"Unary plus hanya membutuhkan heksadesimal" Bukankah maksud Anda desimal?
krillgar
0

Hati-hati, parseInt lebih cepat dari + operator unary di Node.JS, salah bahwa + atau | 0 lebih cepat, mereka lebih cepat hanya untuk elemen NaN.

Lihat ini:

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
sumber
-3

Pertimbangkan kinerja juga. Saya terkejut bahwa parseIntmengalahkan unary plus di iOS :) Ini membantu untuk aplikasi web dengan konsumsi CPU saja. Sebagai aturan umum saya menyarankan JS opt-guys untuk mempertimbangkan operator JS lebih dari operator lain dari sudut pandang kinerja mobile saat ini.

Jadi, go mobile-first ;)

Arman McHitarian
sumber
Seperti yang dijelaskan oleh posting lain, mereka melakukan hal yang sangat berbeda, sehingga Anda tidak dapat dengan mudah bertukar satu dengan yang lain ...
Bergi
@Bergi, benar, tetapi mereka juga memiliki banyak kesamaan. Katakan padaku hanya satu solusi kinerja dalam JavaScript yang jelas merupakan satu-satunya pilihan yang tepat? Secara umum itu sebabnya aturan praktis ada di luar sana untuk kita. Sisanya adalah tugas khusus.
Arman McHitarian
3
@ArmanMcHitaryan ini adalah mikrooptimisasi yang tidak berguna dan tidak layak. Lihat artikel ini - fabien.potencier.org/article/8/…
webvitaly
@webvitaly, artikel yang bagus. Selalu ada orang yang sangat berorientasi perf di luar sana yang hanya suka menulis kode "yang tercepat mungkin" dan dalam beberapa proyek tertentu itu tidak buruk. Itu sebabnya saya menyebutkan "JS opt-guys untuk dipertimbangkan". ini bukan HARUS tentu saja :), tapi saya sendiri merasa jauh lebih mudah dibaca.
Arman McHitarian
Apakah Anda memiliki kutipan untuk ini? Tautan Anda rusak.
djechlin