JavaScript

Belum masuk. Progresmu tidak tersimpan.

Masuk
  • Bab 7 dari 12
  • 25 menit
  • 1 latihan kode
  • 4 soal kuis

Error Handling dan JSON

Di bab ini (10 bagian)
  1. Tujuan
  2. Error itu bukan musuh
  3. Empat jenis error yang sering kamu temui
  4. try, catch, finally
  5. Melempar error sendiri dengan throw
  6. Error kustom singkat
  7. JSON: bahasa pertukaran data
  8. Menangani JSON yang tidak valid
  9. Kesalahan umum
  10. Rangkuman

Tujuan bab ini

  • Mengenali empat jenis error bawaan yang paling sering muncul: SyntaxError, ReferenceError, TypeError, dan RangeError.
  • Menangkap error dengan try, catch, dan finally supaya program tidak berhenti total.
  • Melempar error sendiri dengan throw new Error() dan membuat kelas error kustom sederhana.
  • Mengubah objek menjadi teks JSON dan sebaliknya, termasuk menangani JSON yang tidak valid.

Error itu bukan musuh

Setiap program pasti pernah ketemu error. Bedanya, program yang baik tahu apa yang harus dilakukan saat error terjadi. Bayangkan aplikasi ojek online yang langsung blank cuma karena satu data alamat rusak dari server. Nyebelin, kan? Lebih baik aplikasi menampilkan pesan "Alamat tidak terbaca, coba lagi" dan tetap bisa dipakai.

Di JavaScript, error adalah objek. Setiap objek error punya minimal dua properti penting:

  • name: jenis errornya, misalnya "TypeError".
  • message: penjelasan singkat apa yang salah.

Kalau error tidak ditangkap, JavaScript berhenti menjalankan kode di bawahnya dan mencetak pesan merah di console. Di browser, sisa script di file itu tidak jalan. Di Node.js, prosesnya langsung keluar.

Empat jenis error yang sering kamu temui

JenisKapan munculContoh pemicu
SyntaxErrorKode tidak sesuai aturan tata bahasa JavaScriptKurung kurawal tidak ditutup, JSON.parse("{nama}")
ReferenceErrorMemakai variabel yang tidak adaconsole.log(totl) padahal namanya total
TypeErrorOperasi tidak cocok dengan tipe nilainyaMemanggil undefined() atau membaca properti dari null
RangeErrorNilai di luar rentang yang diizinkannew Array(-1), (3.14).toFixed(200)

Contoh nyata masing-masing:

// ReferenceError
try {
  console.log(hargaTotal);
} catch (e) {
  console.log(e.name);    // ReferenceError
  console.log(e.message); // hargaTotal is not defined
}

// TypeError
try {
  const user = null;
  console.log(user.nama);
} catch (e) {
  console.log(e.name); // TypeError
  // message: Cannot read properties of null (reading 'nama')
}

// RangeError
try {
  new Array(-1);
} catch (e) {
  console.log(e.name);    // RangeError
  console.log(e.message); // Invalid array length
}

Satu catatan soal SyntaxError: kalau kesalahan tata bahasanya ada di kode kamu sendiri (misalnya lupa kurung tutup), seluruh file gagal dibaca sebelum satu baris pun dijalankan. Jadi try/catch di file yang sama tidak bisa menolongnya. SyntaxError yang bisa ditangkap biasanya datang dari kode yang dibaca saat program berjalan, contohnya JSON.parse dengan teks rusak.

Pesan error persisnya bisa sedikit berbeda antara Chrome, Firefox, dan Node.js. Yang pasti sama adalah name-nya.

try, catch, finally

Strukturnya seperti ini:

try {
  // kode yang mungkin error
} catch (error) {
  // dijalankan HANYA jika ada error di blok try
} finally {
  // SELALU dijalankan, error atau tidak
}

Cara kerjanya langkah demi langkah:

  1. JavaScript menjalankan isi try dari atas ke bawah.
  2. Begitu ada error, sisa baris di try dilewati, lalu loncat ke catch. Objek errornya masuk ke parameter error.
  3. Kalau tidak ada error sama sekali, catch dilewati.
  4. finally jalan di akhir dalam dua kondisi itu. Cocok untuk "beres-beres": menutup loading spinner, menutup koneksi, atau mencatat log.
function bagiAman(a, b) {
  try {
    console.log("Mulai menghitung");
    const hasil = a.toFixed(2) / b;
    console.log("Hasil:", hasil);
  } catch (error) {
    console.log("Gagal:", error.name);
  } finally {
    console.log("Selesai diproses");
  }
}

bagiAman(10, 2);
// Mulai menghitung
// Hasil: 5
// Selesai diproses

bagiAman("10", 2);
// Mulai menghitung
// Gagal: TypeError
// Selesai diproses

Pada panggilan kedua, "10".toFixed tidak ada karena string tidak punya method itu, jadi terjadi TypeError. Baris console.log("Hasil:") tidak pernah jalan.

Sejak ES2019, kalau kamu tidak butuh objek errornya, parameter catch boleh dihilangkan: catch { ... }.

Melempar error sendiri dengan throw

Kadang kodenya tidak error secara teknis, tapi datanya salah secara logika. Misalnya umur bernilai -5. JavaScript tidak akan protes, jadi kamu yang harus protes dengan throw.

function setUmur(umur) {
  if (typeof umur !== "number" || umur < 0) {
    throw new Error("Umur harus angka positif");
  }
  return umur;
}

try {
  setUmur(-5);
} catch (e) {
  console.log(e.message); // Umur harus angka positif
}

throw langsung menghentikan fungsi, mirip return, tapi alirannya meloncat ke catch terdekat. Selalu lempar objek Error (bukan string biasa seperti throw "salah") supaya kamu dapat message, name, dan stack untuk melacak baris asal error.

Kamu juga bisa melempar jenis yang lebih spesifik, misalnya throw new TypeError("Harus angka") atau throw new RangeError("Maksimal 100").

Error kustom singkat

Untuk aplikasi yang lebih besar, membuat jenis error sendiri membantu membedakan "salah input user" dari "bug di kode". Caranya dengan class yang mewarisi Error. Detail class dibahas di bab berikutnya, cukup pahami polanya:

class ValidasiError extends Error {
  constructor(pesan) {
    super(pesan);
    this.name = "ValidasiError";
  }
}

try {
  throw new ValidasiError("Email wajib diisi");
} catch (e) {
  if (e instanceof ValidasiError) {
    console.log("Tampilkan ke user:", e.message);
  } else {
    throw e; // bukan urusan kita, lempar lagi
  }
}
// Tampilkan ke user: Email wajib diisi

Perhatikan throw e di bagian else. Itu disebut rethrow: kita hanya menangani error yang kita kenal, sisanya dibiarkan naik ke atas.

JSON: bahasa pertukaran data

JSON (JavaScript Object Notation) adalah format teks untuk mengirim data, misalnya dari server ke aplikasi. Bentuknya mirip objek JavaScript, tapi aturannya lebih ketat:

  • Nama properti wajib pakai kutip dua: "nama", bukan nama atau 'nama'.
  • String juga wajib kutip dua.
  • Tidak boleh ada koma di akhir ([1, 2,] tidak valid).
  • Tidak ada undefined, fungsi, atau komentar.

Dua fungsi utamanya:

const mhs = { nama: "Rudi", umur: 22, hobi: ["futsal", "game"] };

const teks = JSON.stringify(mhs);
console.log(teks);
// {"nama":"Rudi","umur":22,"hobi":["futsal","game"]}
console.log(typeof teks); // string

const kembali = JSON.parse(teks);
console.log(kembali.hobi[1]); // game

// Argumen ketiga: indentasi agar mudah dibaca
console.log(JSON.stringify({ a: 1 }, null, 2));
// {
//   "a": 1
// }

Satu jebakan: JSON.stringify diam-diam membuang properti bernilai undefined dan fungsi.

console.log(JSON.stringify({ a: 1, b: undefined, c() {} })); // {"a":1}

Menangani JSON yang tidak valid

Data dari luar (server, localStorage, input user) tidak bisa dipercaya 100%. JSON.parse melempar SyntaxError kalau teksnya rusak, jadi bungkus selalu dengan try/catch:

function bacaJSON(teks, cadangan = null) {
  try {
    return JSON.parse(teks);
  } catch (e) {
    console.log("JSON rusak:", e.name);
    return cadangan;
  }
}

console.log(bacaJSON('{"tema":"gelap"}')); // { tema: 'gelap' }
console.log(bacaJSON("{tema: gelap}"));    // JSON rusak: SyntaxError lalu null
console.log(bacaJSON("", {}));            // JSON rusak: SyntaxError lalu {}

Dengan pola ini aplikasi tetap jalan memakai nilai cadangan, bukan crash.

Kesalahan umum

  • Membungkus semua kode dengan satu try raksasa. Kamu jadi tidak tahu baris mana yang bermasalah. Bungkus bagian yang memang berisiko saja.
  • catch kosong tanpa tindakan. Error ditelan diam-diam dan bug jadi susah dicari. Minimal catat dengan console.error.
  • throw "teks" alih-alih throw new Error("teks"). Kamu kehilangan name dan stack.
  • Lupa bahwa JSON.parse menghasilkan objek baru. Mengubah hasilnya tidak mengubah teks aslinya.
  • Menulis JSON dengan kutip satu. JSON.parse("{'a':1}") langsung SyntaxError.

Rangkuman

  • Error adalah objek dengan name dan message; jenis yang sering muncul adalah SyntaxError, ReferenceError, TypeError, dan RangeError.
  • try menjalankan kode berisiko, catch menangani error, finally selalu jalan di akhir.
  • throw new Error("pesan") menghentikan fungsi dan meloncat ke catch terdekat; class X extends Error membuat error kustom.
  • JSON.stringify mengubah nilai menjadi teks, JSON.parse mengubah teks menjadi nilai.
  • Selalu bungkus JSON.parse untuk data dari luar dengan try/catch dan sediakan nilai cadangan.

Selesaikan bab ini

  1. 1. Baca materi
  2. 2. Latihan kode (1)
  3. 3. Kuis (4 soal)

Latihan kode: Pembaca JSON yang tidak gampang crash

Lengkapi dua fungsi berikut:

  • bacaJSON(teks, cadangan) mengembalikan hasil JSON.parse(teks). Kalau teksnya bukan JSON valid, jangan sampai error keluar: kembalikan cadangan. Contoh: bacaJSON('{"tema":"gelap"}', null).tema menghasilkan "gelap", sedangkan bacaJSON('{tema: gelap}', 'x') menghasilkan "x".
  • cekUmur(umur) mengembalikan umur bila berupa angka dari 0 sampai 150. Selain itu, lempar new RangeError("Umur tidak valid").

Cek pemahaman

  1. 1Error jenis apa yang muncul saat kode membaca properti dari nilai null, misalnya `user.nama` ketika `user` bernilai null?

  2. 2Blok finally tetap dijalankan walaupun tidak ada error di blok try.

  3. 3Apa yang ditampilkan kode berikut di console?

    try {
      JSON.parse("{'a': 1}");
      console.log("A");
    } catch (e) {
      console.log(e.name);
    } finally {
      console.log("C");
    }
  4. 4Apa hasil `JSON.stringify({ a: 1, b: undefined })`?