Dua chapter terakhir memperlakukan galat seperti satu teks pesan yang lewat di layar. Padahal setiap Error yang dilempar engine adalah object yang berisi informasi terstruktur: jenis galatnya, penjelasannya, dan jejak lokasi kejadian. Ketika galat tertangkap di catch, object itu utuh di tangan kita — dan penanganan yang tepat dimulai dari membaca isinya dengan benar.

Chapter ini membedah anatomi Error, memperkenalkan empat turunannya yang paling sering ditemui, lalu menutup dengan fitur cause untuk merekam akar masalah.

Anatomi: name, message, dan stack #

Membuat Error sama mudahnya dengan membuat object biasa: new Error("pesan"). Instance yang dihasilkan punya tiga properti utama:

js
const galat = new Error("Data pesanan tidak ditemukan");

console.log(galat.name);
console.log(galat.message);
console.log(typeof galat.stack);

Output yang Dihasilkan:

text
Error
Data pesanan tidak ditemukan
string

Ketiganya punya peran masing-masing:

  • name — jenis galat: "Error" untuk instance dasar. Nilai inilah yang muncul di depan transkrip, dan inilah yang biasa diperiksa untuk membedakan jenis kegagalan.
  • message — penjelasan yang ditulis saat pembuatan: "Data pesanan tidak ditemukan". Pesan yang baik menyebut apa yang salah dan nilai apa yang terlibat.
  • stack — sebuah string berisi daftar pemanggil, dari lokasi kegagalan sampai titik masuk program. Membacanya mendalam dibahas di chapter terakhir section ini; untuk saat ini cukup diketahui bahwa properti itu ada dan bertipe string, serta terisi otomatis tanpa perintah apa pun dari kita.

Sampai jumpa cause di bagian akhir, tiga properti inilah seluruh isi standar sebuah Error.

Dua cara menampilkannya juga perlu dikenali. Menggabungkan name dan message sebagai satu string adalah bentuk yang sama dengan transkrip Node — dan itu bukan kebetulan, karena String(galat) memang merakit keduanya:

js
const galat = new Error("Data pesanan tidak ditemukan");

console.log(String(galat));

Output yang Dihasilkan:

text
Error: Data pesanan tidak ditemukan

Sementara itu, console.log(galat) pada object galat mencetak string stack lengkap — bukan isi object seperti pada object biasa. Karena itu di dalam catch kita biasanya mencetak error.message untuk ringkasan, dan mencetak object galatnya utuh hanya saat jejak at ... memang dibutuhkan.

Terakhir, ingat bahwa Error tetap sebuah object: properti tambahan boleh dilekatkan sesuai kebutuhan pelaporan:

js
const galat = new Error("Data pesanan tidak ditemukan");

galat.kode = "PES-404";
galat.idPesanan = 1038;

console.log(galat.kode);
console.log(galat.idPesanan);

Output yang Dihasilkan:

text
PES-404
1038

Polanya dipakai untuk melabeli galat dengan konteks aplikasi — kode kesalahan, id data yang terlibat — tanpa mengubah name maupun message-nya.

Satu keunikan constructor terakhir: Error juga berfungsi tanpa new. Pemanggilan biasa tetap menghasilkan instance yang utuh — perilaku yang tidak dimiliki kebanyakan constructor lain:

js
const tanpaNew = Error("pesan tanpa new");

console.log(tanpaNew instanceof Error);
console.log(tanpaNew.message);

Output yang Dihasilkan:

text
true
pesan tanpa new

Meski sah, tuliskan new Error(...) secara konsisten — bentuk itu menyatakan niat membuat instance secara eksplisit dan tetap menjadi gaya yang paling umum ditemui.

Empat Turunan Error yang Paling Sering Ditemui #

Error hanyalah akar. Engine melempar turunan-turunannya sesuai jenis masalah, dan masing-masing membawa name sendiri:

JenisKapan munculContoh situasi
TypeErrorOperasi tidak cocok dengan tipe nilaiMembaca properti dari null atau undefined
RangeErrorNilai di luar rentang yang diizinkanDigit toFixed lebih dari 100
ReferenceErrorMengakses nama yang tidak pernah dideklarasikanSalah ketik nama variabel
SyntaxErrorTeks tidak sah secara tata bahasaJSON.parse menemui string bukan JSON

Berkas berikut memicu keempatnya secara nyata, satu per satu, lalu mencatat name dan message-nya:

// keluarga-galat.js
// Empat turunan Error yang paling sering ditemui, dipicu satu per satu.

function selidiki(label, aksi) {
  try {
    aksi();
  } catch (error) {
    console.log(label + " -> " + error.name + ": " + error.message);
  }
}

selidiki("membaca properti dari null", () => {
  const keranjang = null;
  return keranjang.total;
});

selidiki("angka di luar batas", () => {
  (10).toFixed(101);
});

selidiki("variabel tidak pernah dideklarasikan", () => {
  return totalBelanja;
});

selidiki("JSON rusak", () => {
  JSON.parse("{ tidak valid }");
});

Output yang Dihasilkan:

text
membaca properti dari null -> TypeError: Cannot read properties of null (reading 'total')
angka di luar batas -> RangeError: toFixed() digits argument must be between 0 and 100
variabel tidak pernah dideklarasikan -> ReferenceError: totalBelanja is not defined
JSON rusak -> SyntaxError: Expected property name or '}' in JSON at position 2 (line 1 column 3)

Mari kita telaah polanya:

  1. Baris 12–15 (selidiki("membaca properti dari null", ...)): callback membaca keranjang.total dari null, sehingga engine melempar TypeError. Pesannya presisi: (reading 'total') menyebut properti apa yang dicoba dibaca dari nilai apa.
  2. Baris 17–19 (selidiki("angka di luar batas", ...)): toFixed hanya menerima digit 0 sampai 100; permintaan 101 di luar rentang itu memicu RangeError. Kelas galat yang sama muncul untuk panjang array negatif dan repeat dengan hitungan minus.
  3. Baris 21–23 (selidiki("variabel tidak pernah dideklarasikan", ...)): totalBelanja tidak pernah dideklarasikan, sehingga pencarian nama gagal — ReferenceError: totalBelanja is not defined. Pesan seperti ini hampir selalu berarti salah ketik.
  4. Baris 25–27 (selidiki("JSON rusak", ...)): JSON.parse menolak { tidak valid } karena nama properti JSON wajib diapit tanda kutip ganda. Catatan menarik: galat parsing yang terjadi saat program berjalan tetap berupa SyntaxError — bedanya dengan chapter pertama, galat ini terlempar saat runtime dan bisa ditangkap.
  5. Baris 4–10 (function selidiki(label, aksi) { ... }): helper kecil ini mengemas pola pemeriksaan: jalankan aksi(), tangkap galatnya, cetak name dan message. Tanpa helper, kita perlu empat blok try-catch terpisah.

Mengenali jenis galat ini mempercepat diagnosis. ReferenceError mengarah ke kesalahan penulisan nama; TypeError mengarah ke nilai null/undefined yang belum dijaga; RangeError mengarah ke argumen di luar batas.

Selain keempatnya, spesifikasi masih menyiapkan EvalError dan URIError, tetapi keduanya jarang kita temui di kode modern — engine saat ini hampir tidak melemparnya lagi, dan daftar empat di atas sudah menutup hampir semua kejadian sehari-hari.

Cara membaca tabel di atas juga perlu dibalik: keempat jenis itu dilempar engine, sedangkan yang kita tulis sendiri sejauh ini adalah Error generik lewat new Error(...). Pembagian kerjanya jelas — galat perilaku bahasa diserahkan ke engine dengan jenisnya yang presisi, sementara pelanggaran aturan aplikasi kita lempar sendiri. Ketika kebutuhannya makin spesifik, chapter Custom Errors menunjukkan cara membuat jenis baru dengan name milik aplikasi.

cause: Merekam Akar Masalah #

Sering kali sebuah galat adalah akibat dari galat lain: parsing konfigurasi gagal karena JSON-nya rusak. Tanpa perekaman, galat pembungkus hanya bisa menulis konteksnya di message sebagai teks, dan galat asalnya terputus dari rantai. Sejak ES2022, constructor Error menerima argumen kedua berupa object opsi, dan properti cause-nya menyimpan galat asal:

js
function bacaPengaturan(json) {
  try {
    return JSON.parse(json);
  } catch (error) {
    throw new Error("Pengaturan gagal dibaca", { cause: error });
  }
}

try {
  bacaPengaturan("{ masih rusak }");
} catch (error) {
  console.log(error.message);
  console.log("Penyebab:", error.cause.name, "-", error.cause.message);
}

Output yang Dihasilkan:

text
Pengaturan gagal dibaca
Penyebab: SyntaxError - Expected property name or '}' in JSON at position 2 (line 1 column 3)

Pola di atas menangkap galat asli, membungkusnya dengan pesan konteks yang lebih bermakna, lalu menyimpan galat aslinya utuh di error.cause. Pemanggil di lapisan atas bisa memilih: cukup baca message, atau telusuri cause bila perlu diagnosis lebih dalam. Dengan begitu konteks lapisan atas dan detail lapisan bawah sama-sama terjaga di satu object.

Jenis galat bawaan mencakup banyak kebutuhan, tetapi semuanya generik. TypeError tidak memberi tahu apakah yang gagal itu kupon, saldo, atau sesi login — semua hanya “bukan tipe yang cocok”. Chapter berikutnya menunjukkan cara membuat jenis galat milik aplikasi sendiri, lengkap dengan name yang bermakna, sehingga penanganan bisa memutuskan berdasarkan jenis kegagalan yang sebenarnya.

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

keluarga-galat.js

Unduh berkas
javascript
// keluarga-galat.js
// Empat turunan Error yang paling sering ditemui, dipicu satu per satu.

function selidiki(label, aksi) {
  try {
    aksi();
  } catch (error) {
    console.log(label + " -> " + error.name + ": " + error.message);
  }
}

selidiki("membaca properti dari null", () => {
  const keranjang = null;
  return keranjang.total;
});

selidiki("angka di luar batas", () => {
  (10).toFixed(101);
});

selidiki("variabel tidak pernah dideklarasikan", () => {
  return totalBelanja;
});

selidiki("JSON rusak", () => {
  JSON.parse("{ tidak valid }");
});