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:
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 jugaBukan 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:
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 pakaiContoh 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:
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-100Kombinasi private + setter adalah pola enkapsulasi yang lengkap: data disembunyikan, setiap perubahan melewati validasi.
Jebakan umum
#adalah bagian dari nama.this.#saldodanthis.saldoadalah dua properti berbeda. Typo satu karakter membuat bug yang membingungkan.- Private tidak bisa diakses subclass. Berbeda dengan bahasa seperti Java yang punya
protected, di JavaScript#fieldmilik induk tidak terlihat oleh class anak. Rencanakan API induk dengan baik. - Static tidak bisa pakai
thisinstance. Di dalam static method,thismerujuk ke class-nya, bukan ke instance. Jangan coba aksesthis.namadi sana. - 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.
export default function App(): JSX.Element { return <h1>Hello world</h1> }
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?