Satu Tipe Number untuk Segalanya (Hampir)
Kebanyakan bahasa memberimu tipe terpisah untuk integer dan float. JavaScript, secara historis, hanya memberimu satu: Number. Entah kamu menulis 42, 3.14, atau -0.001, kamu mendapat tipe primitif yang sama, yaitu float double-precision IEEE 754 64-bit.
Itu praktis: tidak perlu konversi antara int dan float, tidak ada overflow di 2^31. Tetapi representasi float punya konsekuensi, dan konsekuensi itu sering menjebak pemula. Tipe numerik kedua, BigInt, ditambahkan pada 2020 untuk menangani kasus-kasus di mana Number tidak memadai.
Kejutan Floating-Point
Jalankan ini:
Baris pertama mencetak 0.30000000000000004. Baris kedua mencetak false. Ini bukan keanehan JavaScript: Python, Java, C, dan bahasa apa pun yang memakai float IEEE 754 berperilaku sama.
Alasannya: 0.1 dan 0.2 tidak bisa direpresentasikan secara tepat dalam biner, sama seperti 1/3 tidak bisa ditulis secara tepat dalam desimal. Yang disimpan adalah pendekatan biner yang paling dekat, dan kesalahan kecil pun menumpuk. Model mentalnya: perlakukan nilai Number yang melibatkan desimal sebagai pendekatan yang kebetulan sangat dekat dengan apa yang kamu tulis.
Untuk uang, jangan simpan $19.99 sebagai 19.99. Simpan sen sebagai integer, yaitu 1999, lalu format saat ditampilkan. Itulah satu kebiasaan terbaik untuk menghindari bug float.
Membandingkan Float dengan Aman
Karena kesamaan tidak bisa diandalkan, bandingkan dengan toleransi saat kamu perlu:
Number.EPSILON adalah selisih terkecil antara 1 dan angka berikutnya yang bisa direpresentasikan, toleransi default yang wajar untuk nilai di sekitar 1. Untuk besaran yang sangat besar atau sangat kecil, kamu butuh toleransi yang menyesuaikan dengan input-nya.
Rentang Integer yang Aman
Integer sampai ukuran tertentu memang tepat dalam float 64-bit. Setelah itu, presisinya mulai hilang sedikit demi sedikit:
2^53 - 1 adalah integer terakhir di mana setiap integer di bawahnya bisa direpresentasikan. Di atasnya, sebagian integer sama sekali tidak ada di tipe Number: nilainya dibulatkan ke tetangga terdekatnya. Itu bug perusakan data diam-diam yang tinggal menunggu waktu kalau kamu mem-parsing ID 64-bit dari database sebagai angka JSON biasa.
Kenalan dengan BigInt
BigInt adalah tipe primitif tersendiri untuk integer dengan presisi tak terbatas. Kamu membuatnya dengan menambahkan n pada literal integer, atau dengan memanggil BigInt(...):
BigInt tidak punya batas atas selain memori yang tersedia. BigInt adalah alat yang tepat untuk:
- ID database atau snowflake ID Twitter/X yang melebihi
2^53. - Perhitungan kriptografi.
- Aritmetika integer apa pun di mana hasil yang tepat lebih penting daripada kecepatan mentah.
BigInt bukan alat yang tepat untuk counter sehari-hari, index array, atau uang dalam bentuk sen: Number biasa lebih cepat dan bisa bekerja sama dengan setiap API di bahasa ini.
Aritmetika BigInt
Semua operator yang biasa tetap berfungsi, asalkan kedua operand-nya BigInt:
Pembagian dibulatkan ke arah nol: tidak ada BigInt pecahan. Kalau kamu butuh pecahan, kamu kembali ke wilayah Number (atau memakai library desimal).
Jangan Campur Tipe
Aturan yang sering menjebak: kamu tidak bisa mencampur Number dan BigInt dalam ekspresi yang sama.
Perbandingan adalah satu-satunya pengecualian: <, >, == melakukan coercion lintas tipe:
Jadi == menganggap keduanya sama, === tidak. Kalau kamu sudah memakai === di mana-mana (dan memang sebaiknya begitu), anggap perbandingan numerik antara kedua tipe ini sebagai tanda desain yang bermasalah: pilih satu sisi dan lakukan konversi.
Konversi di Antara Keduanya
Dua konversi, dua jebakan:
Konversi Number → BigInt itu ketat: desimal dan NaN memunculkan error. Konversi BigInt → Number lebih longgar tetapi bisa kehilangan data: apa pun di atas MAX_SAFE_INTEGER akan dibulatkan. Kalau kamu mengonversi BigInt yang kamu terima dari server, tanyakan pada dirimu apakah kamu benar-benar perlu melakukannya.
Nilai Number Khusus
Sekalian di sini, ada tiga nilai di tipe Number yang bukan angka dalam arti matematis:
Infinity dan -Infinity muncul saat kamu membagi dengan nol atau melampaui rentang float. NaN ("not a number") muncul saat operasi aritmetika tidak menghasilkan hasil yang bermakna.
NaN terkenal tidak sama dengan dirinya sendiri. Itu bagian dari spesifikasi IEEE 754, bukan bug JS. Pakai Number.isNaN(x) untuk mengeceknya. isNaN global yang lebih lama mengubah argumennya terlebih dulu, sehingga memberi jawaban yang salah (isNaN("hello") mengembalikan true). Selalu utamakan versi Number.isNaN.
Mem-parsing Angka dari String
Input pengguna dan angka JSON sering datang sebagai string. Ada tiga cara untuk mengonversinya:
Number() itu ketat: apa pun yang bukan angka menghasilkan NaN, kecuali string kosong dan spasi, yang menghasilkan 0. parseInt dan parseFloat lebih pemaaf: keduanya membaca sejauh mungkin lalu berhenti. Pilih yang sesuai dengan maksudmu, dan cek NaN sebelum memakai hasilnya.
Untuk mem-parsing BigInt dari string, pakai BigInt("123"): ketat dan memunculkan error untuk input yang buruk.
Buku Aturan Singkat
- Untuk counter, matematika, koordinat, dan sebagian besar angka sehari-hari: pakai
Number. - Untuk uang: ubah ke sen dalam bentuk integer dan pakai
Number, atau gunakan library desimal. - Untuk integer yang lebih besar dari
2^53(ID database, kripto, kombinatorika): pakaiBigIntdengan akhirann. - Bandingkan float dengan toleransi, bukan
===. - Cek hasil yang tidak valid dengan
Number.isNaNdanNumber.isFinite, bukan versi globalnya. - Jangan campur
NumberdanBigIntdalam ekspresi yang sama: lakukan konversi secara eksplisit.
Berikutnya: null vs undefined
JavaScript punya dua cara untuk mengatakan "tidak ada nilai", yaitu null dan undefined, dan keduanya tidak bisa saling menggantikan. Berikutnya: arti masing-masing, perbedaannya, dan kapan memakai yang mana.
Pertanyaan yang sering diajukan
Mengapa 0.1 + 0.2 tidak sama dengan 0.3 di JavaScript?
Karena tipe Number di JavaScript adalah float IEEE 754 64-bit, dan 0.1 serta 0.2 tidak bisa direpresentasikan secara tepat dalam biner. Hasilnya 0.30000000000000004. Ini bukan bug JavaScript: hal yang sama terjadi di Python, Java, dan bahasa lain yang memakai format float yang sama. Untuk uang, ubah ke integer (sen) atau pakai library desimal.
Apa itu BigInt di JavaScript dan kapan sebaiknya memakainya?
BigInt adalah tipe primitif numerik tersendiri untuk integer yang melebihi Number.MAX_SAFE_INTEGER (2^53 - 1). Buat dengan akhiran n, seperti 9007199254740993n, atau dengan BigInt(value). Pakai untuk ID database 64-bit, kriptografi, atau perhitungan integer apa pun di mana presisi lebih penting daripada kecepatan.
Bisakah aku mencampur Number dan BigInt di JavaScript?
Tidak bisa. 1n + 1 memunculkan TypeError: Cannot mix BigInt and other types. Ubah secara eksplisit dengan BigInt(n) atau Number(b). Operator perbandingan seperti < dan == memang berfungsi di antara keduanya, tetapi === mengembalikan false karena tipenya berbeda.