mahiroopclassMahir3 mnt baca

Private, Static, Getter dan Setter

Class dasar menyimpan semua properti secara terbuka: siapa pun bisa menulis akun.saldo = 999999999 dan merusak data. Di aplikasi nyata, sebagian data harus dilindungi dan sebagian perilaku milik class-nya, bukan insta...

Private, Static, Getter dan Setter

Class dasar menyimpan semua properti secara terbuka: siapa pun bisa menulis akun.saldo = 999999999 dan merusak data. Di aplikasi nyata, sebagian data harus dilindungi dan sebagian perilaku milik class-nya, bukan instance-nya. Tiga fitur ini menjawabnya: #private, static, dan getter/setter.

Kenapa enkapsulasi ada

Enkapsulasi berarti menyembunyikan detail internal dan hanya membuka "pintu" yang aman. Saldo rekening boleh dibaca dan diubah lewat setor/tarik yang punya aturan, tapi tidak boleh ditimpa langsung. Tanpa enkapsulasi, setiap bagian kode bisa mengubah data sesukanya, dan bug "kok saldonya berubah sendiri" jadi mimpi buruk dilacak. Private field memaksa semua perubahan lewat jalur resmi yang kamu sediakan.

#private: benar-benar tidak bisa diakses dari luar

Tambahkan # di depan nama properti atau method. JavaScript akan melempar error kalau diakses dari luar class:

javascript
class Rekening {
  #saldo = 0; // private field

  constructor(nama) {
    this.nama = nama;
  }

  setor(jumlah) {
    if (jumlah <= 0) throw new Error("Nominal harus positif");
    this.#saldo += jumlah;
  }

  tarik(jumlah) {
    if (jumlah > this.#saldo) throw new Error("Saldo tidak cukup");
    this.#saldo -= jumlah;
  }

  getSaldo() {
    return this.#saldo;
  }
}

const rek = new Rekening("Budi");
rek.setor(50000);
console.log(rek.getSaldo()); // 50000
// rek.#saldo = 1000000; // SyntaxError: tidak bisa diakses
// console.log(rek.#saldo); // SyntaxError juga

Bukan cuma konvensi penamaan seperti _saldo (yang sebenarnya masih bisa diakses), #saldo ditegakkan oleh bahasa itu sendiri. Aturan bisnis "tidak boleh tarik melebihi saldo" kini mustahil dilanggar dari luar.

static: milik class, bukan instance

Method atau properti static dipanggil lewat nama class-nya, tanpa new. Cocok untuk fungsi utilitas atau data yang sama untuk semua instance:

javascript
class MatematikaWarung {
  static PAJAK = 0.11;

  static hitungTotal(hargaSatuan, jumlah) {
    const subtotal = hargaSatuan * jumlah;
    return subtotal + subtotal * MatematikaWarung.PAJAK;
  }
}

console.log(MatematikaWarung.hitungTotal(8000, 3)); // 26400
// tanpa new, langsung pakai

Contoh lain yang umum: Math.random(), JSON.parse(), Array.isArray(), semuanya static. Kalau fungsinya tidak butuh data spesifik satu instance, jadikan static.

Getter dan setter: properti dengan logika

Getter/setter membuat method terlihat seperti properti biasa, tapi diam-diam menjalankan validasi:

javascript
class Siswa {
  #nilai = [];

  set tambahNilai(n) {
    if (n < 0 || n > 100) throw new Error("Nilai harus 0-100");
    this.#nilai.push(n);
  }

  get rataRata() {
    if (this.#nilai.length === 0) return 0;
    return this.#nilai.reduce((a, b) => a + b, 0) / this.#nilai.length;
  }

  get jumlahNilai() {
    return this.#nilai.length;
  }
}

const ani = new Siswa();
ani.tambahNilai = 80; // terlihat seperti assignment, tapi lewat setter
ani.tambahNilai = 90;
console.log(ani.rataRata);    // 85, tanpa tanda kurung
// ani.tambahNilai = 150;     // Error: Nilai harus 0-100

Kombinasi private + setter adalah pola enkapsulasi yang lengkap: data disembunyikan, setiap perubahan melewati validasi.

Jebakan umum

  1. # adalah bagian dari nama. this.#saldo dan this.saldo adalah dua properti berbeda. Typo satu karakter membuat bug yang membingungkan.
  2. Private tidak bisa diakses subclass. Berbeda dengan bahasa seperti Java yang punya protected, di JavaScript #field milik induk tidak terlihat oleh class anak. Rencanakan API induk dengan baik.
  3. Static tidak bisa pakai this instance. Di dalam static method, this merujuk ke class-nya, bukan ke instance. Jangan coba akses this.nama di sana.
  4. Getter/setter yang berat. Karena terlihat seperti akses properti biasa, orang tidak menyangka ada komputasi mahal di baliknya. Jaga getter tetap cepat, atau jadikan method biasa supaya biayanya eksplisit.
Live Playground
export default function App(): JSX.Element {
  return <h1>Hello world</h1>
}

Edit kode di kiri, preview kanan ter-update otomatis.

Tantangan

Dompet Digital Aman

Di dunia nyata, aplikasi dompet digital adalah target empuk bug finansial: satu celah di mana saldo bisa diubah langsung berarti uang palsu. Tantangan ini melatihmu merancang class yang anti-rusak. Buat class Dompet dengan #saldo private, constructor menerima nama pemilik, method isiSaldo(jumlah) (tolak jika <= 0), method bayar(jumlah) (tolak jika saldo kurang), getter saldo, dan static method formatRupiah(angka) yang mengembalikan string "Rp" + format Indonesia.

<!doctype html>
<html>
<head>
<meta charset="utf-8" />

</head>
<body>
<h1>Halo JS</h1>
<p>Buka console preview untuk melihat output.</p>
<script src="index.js"></script>
</body>
</html>

Kuis Bab

Uji pemahamanmu: Fetch, Error & Modul

Jawab 5 soal berikut, lalu tekan "Periksa Jawaban".

1.Mengapa fetch ke URL yang mengembalikan status 404 tidak otomatis masuk ke blok catch?

2.Apa peran blok finally dalam try-catch-finally?

3.Kapan membuat custom error class (misalnya ValidationError extends Error) berguna?

4.Apa perbedaan named export dan default export di ES6 module?

5.Apa gunanya private field (#saldo) di class?