Enam tipe primitive pertama sudah cukup untuk pekerjaan sehari-hari, tetapi dua kebutuhan khusus belum terjawab. Pertama: bagaimana jika presisi penuh di atas batas aman number benar-benar wajib — misalnya nomor transaksi berukuran raksasa pada sistem pembayaran? Kedua: bagaimana jika kita butuh penanda yang dijamin tidak akan tertukar dengan penanda lain, sekalipun teksnya sama persis? JavaScript menjawab keduanya dengan bigint dan Symbol.
Chapter ini memperkenalkan keduanya sebatas kebutuhan pemula: dari mana masing-masing lahir, bagaimana menulis dan memakainya, dan aturan apa yang paling sering menabrak. Keduanya jarang dipakai di awal karier, tetapi mengenali wujudnya membuat kita tidak terkejut saat bertemu di kode orang lain.
bigint: Angka Melebihi Batas Aman #
Chapter Numbers membuktikan bahwa number kehilangan presisi di atas 9007199254740991 — batasAman + 1 dan batasAman + 2 bahkan menghasilkan angka yang sama. Tipe bigint menghilangkan batas itu: angka ditulis dengan akhiran n, dan engine menyimpan seluruh digitnya dengan tepat:
const batasAman = Number.MAX_SAFE_INTEGER;
console.log(batasAman + 1); // 9007199254740992 — masih tepat
console.log(batasAman + 2); // 9007199254740992 — meleset, sama dengan +1
console.log(9007199254740993n + 1n); // tepat, tanpa pembulatan
Output yang Dihasilkan:
9007199254740992
9007199254740992
9007199254740994nBandingkan baris kedua dan ketiga: operasi number menghasilkan angka yang sama untuk +1 dan +2, sedangkan bigint membedakan keduanya dengan sempurna. Aritmetika bigint memakai operator yang sama — +, -, * — tetapi kedua sisi harus sama-sama bigint:
console.log(999999999999999999999n * 999n);Output yang Dihasilkan:
998999999999999999999001nHasil perkalian itu melampaui batas aman number puluhan digit, dan bigint mencatat setiap digitnya utuh. Perhatikan satu detail tampilan: ketika dicetak, Node menampilkan bigint bersama akhiran n-nya, sehingga kita selalu bisa membedakannya dari number di keluaran console.
Konversi dua arah tersedia lewat BigInt() dan Number(), tetapi keduanya perlu diwaspadai:
console.log(BigInt(123)); // 123n
console.log(BigInt("9007199254740993")); // tetap tepat
console.log(Number(9007199254740993n)); // presisi hilang kembali
Output yang Dihasilkan:
123n
9007199254740993n
9007199254740992BigInt("9007199254740993") mempertahankan seluruh digit, tetapi begitu dikonversi kembali menjadi Number, angkanya dibulatkan menjadi 9007199254740992 — masalah presisi yang tadinya teratasi langsung kembali muncul. Aturannya sederhana: angka yang wajib presisi penuh sebaiknya tetap menjadi bigint dari awal sampai akhir.
Aturan Campuran bigint dan number #
Kesalahan yang paling cepat ditemui: mencampur bigint dan number dalam satu perhitungan. Engine menolaknya dengan TypeError, bukan mengonversi salah satunya diam-diam:
try {
console.log(1n + 1);
} catch (error) {
console.log(error.name + ": " + error.message);
}Output yang Dihasilkan:
TypeError: Cannot mix BigInt and other types, use explicit conversionsPesan errornya jelas: gunakan konversi eksplisit, misalnya BigInt(1) + 1n. Penolakan keras ini sengaja dirancang — konversi otomatis bisa menghilangkan presisi tanpa kita sadari, dan presisi justru alasan utama bigint dipakai.
Symbol: Identifier yang Dijamin Unik #
Symbol menjawab kebutuhan yang berbeda: penanda yang dijamin unik. Setiap pemanggilan Symbol() menghasilkan nilai baru yang tidak akan pernah sama dengan symbol lain, sekalipun keterangannya ditulis sama persis:
const idA = Symbol("id");
const idB = Symbol("id");
console.log(idA === idB); // false — dua symbol berbeda
console.log(String(idA)); // Symbol(id)
Output yang Dihasilkan:
false
Symbol(id)Teks "id" di dalam kurung disebut description, dan perannya hanya satu: keterangan untuk manusia saat debugging. Description tidak membuat dua symbol jadi sama — baris pertama membuktikannya dengan false. Perbandingan === pada symbol selalu menanyakan identitas: apakah keduanya hasil pemanggilan Symbol() yang sama. Itulah jaminan uniknya.
Kegunaan utamanya menyusul di section Objects: symbol dipakai sebagai kunci properti yang tidak akan bentrok dengan kunci lain, sekalipun namanya kebetulan sama. Untuk sekarang, cukup kuasai cara pembuatan dan jaminan uniknya.
Aturan Khusus Symbol dan String #
Symbol punya satu aturan yang tidak dimiliki primitive lain: symbol tidak bisa dikonversi menjadi string secara otomatis. Konversi eksplisit dengan String() sah — sudah kita lihat di atas — tetapi penyisipan otomatis melalui penggabungan atau template literal ditolak dengan error:
const idA = Symbol("id");
try {
console.log("Kode: " + idA);
} catch (error) {
console.log(error.name + ": " + error.message);
}Output yang Dihasilkan:
TypeError: Cannot convert a Symbol value to a stringAturan yang sama berlaku di dalam template literal: `Kode: ${idA}` juga memunculkan TypeError: Cannot convert a Symbol value to a string. Penolakan ini disengaja oleh standar bahasa — konversi string yang otomatis mudah menyembunyikan kesalahan pemakaian symbol di tempat yang tidak tepat. Bila teksnya memang dibutuhkan, nyatakan niatnya secara eksplisit dengan String(idA).
Contoh Lengkap: id-unik.js #
Berkas berikut merangkum kedua tipe dalam satu uji: pembuktian presisi bigint, penolakan campuran tipe, keunikan Symbol, dan penolakan konversi otomatisnya:
// id-unik.js
// Membuktikan mengapa JavaScript menyediakan tipe bigint dan symbol.
// --- Number meleset di atas batas aman ---
const batasAman = Number.MAX_SAFE_INTEGER;
console.log(batasAman); // 9007199254740991
console.log(batasAman + 1); // 9007199254740992 — masih tepat
console.log(batasAman + 2); // 9007199254740992 — meleset, sama dengan +1
// --- bigint menjaga presisi berapa pun besar angkanya ---
console.log(9007199254740993n); // 9007199254740993n — tepat, tidak meleset
console.log(9007199254740993n + 1n);
console.log(999999999999999999999n * 999n);
// --- bigint dan number tidak boleh dicampur langsung ---
try {
console.log(1n + 1);
} catch (error) {
console.log(error.name + ": " + error.message);
}
// --- Symbol: setiap pemanggilan menghasilkan nilai yang unik ---
const idA = Symbol("id");
const idB = Symbol("id");
console.log(idA === idB); // false
console.log(String(idA)); // Symbol(id)
// --- Symbol tidak bisa dimasukkan ke string secara otomatis ---
try {
console.log("Kode: " + idA);
} catch (error) {
console.log(error.name + ": " + error.message);
}Output yang Dihasilkan:
9007199254740991
9007199254740992
9007199254740992
9007199254740993n
9007199254740994n
998999999999999999999001n
TypeError: Cannot mix BigInt and other types, use explicit conversions
false
Symbol(id)
TypeError: Cannot convert a Symbol value to a stringMari kita telaah apa yang terjadi pada baris-baris kode di atas:
- Baris 5–8 (
const batasAman = ...dst.):numbertampil baik sampai batas aman, lalu+1dan+2menghasilkan angka yang sama — pembuktian ulang bahwa presisi hilang di atas batas. - Baris 11–13 (
console.log(9007199254740993n);dst.):bigintmencatat9007199254740993tanpa pembulatan, melanjutkan penjumlahannya dengan tepat, dan bahkan mengalikan dua angka dua puluh satu digit dengan utuh. - Baris 16–20 (
try { ... } catch (error) { ... }): perhitungan1n + 1ditolak oleh engine denganTypeError: Cannot mix BigInt and other types, use explicit conversions; blokcatchmenangkapnya agar uji berikutnya tetap berjalan. - Baris 23–26 (
const idA = Symbol("id");dst.): dua symbol dengan description yang sama dibandingkan — hasilnyafalse, bukti jaminan unik.String(idA)menghasilkan teksSymbol(id)yang cocok untuk dicetak. - Baris 29–33 (
try { ... } catch (error) { ... }): penggabungan string dengan symbol ditolakTypeError: Cannot convert a Symbol value to a string— konversi otomatis dilarang, konversi eksplisit tetap tersedia.
Dengan bigint dan Symbol, tujuh tipe primitive kini lengkap kita kenali. Pertanyaan berikutnya muncul secara alami: bagaimana cara memeriksa tipe sebuah nilai saat debugging? Alat resminya adalah operator typeof — topik chapter berikutnya.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
id-unik.js
Unduh berkas// id-unik.js
// Membuktikan mengapa JavaScript menyediakan tipe bigint dan symbol.
// --- Number meleset di atas batas aman ---
const batasAman = Number.MAX_SAFE_INTEGER;
console.log(batasAman); // 9007199254740991
console.log(batasAman + 1); // 9007199254740992 — masih tepat
console.log(batasAman + 2); // 9007199254740992 — meleset, sama dengan +1
// --- bigint menjaga presisi berapa pun besar angkanya ---
console.log(9007199254740993n); // 9007199254740993n — tepat, tidak meleset
console.log(9007199254740993n + 1n);
console.log(999999999999999999999n * 999n);
// --- bigint dan number tidak boleh dicampur langsung ---
try {
console.log(1n + 1);
} catch (error) {
console.log(error.name + ": " + error.message);
}
// --- Symbol: setiap pemanggilan menghasilkan nilai yang unik ---
const idA = Symbol("id");
const idB = Symbol("id");
console.log(idA === idB); // false
console.log(String(idA)); // Symbol(id)
// --- Symbol tidak bisa dimasukkan ke string secara otomatis ---
try {
console.log("Kode: " + idA);
} catch (error) {
console.log(error.name + ": " + error.message);
}