Soal 1Dengan getter yang mengembalikan 30 - this.reserved, apa hasilnya kalau reserved diubah menjadi 20 lalu getter-nya dibaca?
Getter dan Setter — Menjalankan Kode Saat Property Dibaca atau Di-assign
Getter dan setter menjalankan kode saat property dibaca atau di-assign. Membahas computed property, validasi value, setter dari constructor, dan property read-only.
Misalnya halaman pendaftaran seminar menampilkan sisa kursi sebagai "kapasitas − jumlah pendaftar". Kalau sisa kursi dihitung dan disimpan saat instance dibuat, tampilannya tidak berubah walaupun pendaftar bertambah belakangan. Kalau kapasitas diisi value yang lebih kecil dari jumlah pendaftar pun, tidak ada yang mencegahnya.
Artikel ini membahas getter dan setter, yang menjalankan kode saat property dibaca atau di-assign.
Dihitung Ulang Setiap Kali Dibaca — get dan Computed Property
Kalau sisa kursi dihitung sebagai "kapasitas − jumlah pendaftar" di constructor lalu disimpan, value-nya tetap seperti saat dibuat walaupun jumlah pendaftar diubah belakangan. Kalau dijadikan method, value-nya memang bisa dihitung ulang, tapi pemanggilnya harus ingat bahwa kapasitas ditulis tanpa tanda kurung, sedangkan sisa kursi pakai tanda kurung.
Getter (method di dalam class yang diawali get dan berjalan saat property-nya dibaca) ditulis tanpa parameter, seperti get remainingSeats() { ... }, dan value yang di-return menjadi hasil pembacaannya.
Property seperti remainingSeats, yang dihitung dari property lain lalu dikembalikan, disebut computed property.
class Seminar {
reserved = 0; // Jumlah pendaftar
constructor(capacity) {
this.capacity = capacity; // Kapasitas
}
// Dihitung dari kapasitas dan jumlah pendaftar saat itu, setiap kali dibaca
get remainingSeats() {
return this.capacity - this.reserved;
}
}
const seminar = new Seminar(30);
console.log(seminar.remainingSeats); // 30 (dibaca tanpa tanda kurung)
// Baca lagi setelah ada 12 pendaftar
seminar.reserved = 12;
console.log(seminar.remainingSeats); // 18
Angka 30 di baris atas dihitung sekali saat new lalu disimpan. Getter di baris bawah tidak menyimpan value apa pun dan menjalankan ekspresi return setiap kali kamu membaca seminar.remainingSeats, jadi berapa kali pun reserved diubah, kamu tidak perlu menambah baris untuk menghitung ulang sisa kursi.
Memanggil Getter dengan Tanda Kurung Melempar TypeError
Getter ditulis seperti method, tapi pemanggilnya tidak memakai tanda kurung. Kalau kamu menulis seminar.remainingSeats(), angka 18 yang dikembalikan justru dipanggil sebagai function, dan kodenya berhenti dengan TypeError: seminar.remainingSeats is not a function.
Mengecek Value yang Di-assign — set dan Validasi
Menjelang hari seminar, kapasitas kadang dinaikkan dari 30 menjadi 40 karena menyesuaikan tempat. Pengecekan dengan if dan throw di constructor hanya jalan saat new, jadi kalau setelah itu kamu meng-assign seminar.capacity = 5, yang lebih kecil dari 12 pendaftar, tidak ada yang menghentikannya dan sisa kursi tampil sebagai -7.
Setter (method di dalam class yang diawali set dan berjalan saat property-nya di-assign) menerima value yang di-assign lewat parameter value. Value yang sebenarnya disimpan dengan nama lain, seperti _capacity, lalu dikembalikan dari getter dengan nama yang sama, get capacity.
Awalan _ adalah konvensi yang berarti "jangan diubah langsung dari luar".
class Seminar {
constructor(capacity, reserved) {
this.reserved = reserved; // Jumlah pendaftar
this._capacity = capacity; // Value kapasitas yang sebenarnya disimpan di _capacity
}
get capacity() { return this._capacity; }
set capacity(value) { // Value yang di-assign masuk ke value
if (value < this.reserved) {
throw new Error(`Kapasitas tidak boleh kurang dari ${this.reserved} pendaftar: ${value}`);
}
this._capacity = value;
}
}
const seminar = new Seminar(30, 12);
seminar.capacity = 40; // set capacity berjalan dan menyimpan 40
console.log(seminar.capacity); // 40 (get capacity berjalan)
seminar.capacity = 5; // Error: Kapasitas tidak boleh kurang dari 12 pendaftar: 5
=, set yang berjalan; kalau dibaca di tempat lain, get yang berjalan. Value yang tidak lolos pengecekan tidak pernah sampai ke _capacity.Baris ③ berhenti karena throw, jadi kalau tidak dibungkus try, baris-baris di bawahnya tidak dijalankan. Selama kamu meng-assign ke capacity, value-nya selalu lewat setter, tapi kalau kamu langsung menulis seminar._capacity = 5, value-nya masuk tanpa dicek. Cara mencegahnya dibahas di artikel berikutnya.
Assign ke Nama yang Sama di Dalam Setter Melempar RangeError
Kalau kamu menulis this.capacity = value; di dalam set capacity(value), assignment itu memanggil setter lagi, lalu meng-assign lagi, dan seterusnya sampai berhenti dengan RangeError: Maximum call stack size exceeded. Simpan value-nya dengan nama lain, seperti _capacity.
Tetap Lewat Setter Saat Dibuat — Assignment di constructor
Seminar di atas menyimpan value langsung ke _capacity di constructor, jadi new Seminar(5, 12) dibuat tanpa pengecekan. Kalau kamu juga menulis if yang sama di constructor, setiap kali syaratnya berubah kamu harus memperbaiki dua tempat, dan kalau salah satunya terlupa, new dan assignment memberi hasil yang berbeda.
Kalau di dalam constructor kamu meng-assign ke nama tanpa _, seperti this.capacity = capacity, setter juga berjalan untuk baris itu. Pengecekannya tetap di satu tempat, yaitu setter, dan value yang dioper ke new maupun value yang di-assign belakangan dicek dengan syarat yang sama.
class Seminar {
constructor(capacity, reserved) {
this.reserved = reserved; // Simpan dulu jumlah pendaftar yang dipakai pengecekan
this.capacity = capacity; // Namanya tanpa _, jadi set capacity berjalan
}
get capacity() { return this._capacity; }
set capacity(value) {
if (value < this.reserved) {
throw new Error(`Kapasitas tidak boleh kurang dari ${this.reserved} pendaftar: ${value}`);
}
this._capacity = value;
}
}
try {
new Seminar(5, 12); // Saat new pun, value lewat pengecekan setter
} catch (error) {
console.log(error.message); // Kapasitas tidak boleh kurang dari 12 pendaftar: 5
}
new Seminar(5, 12)— memanggil constructor- Exception dari setter kembali sampai ke sini, dan tidak ada instance yang dikembalikan
this.reserved = 12— menyimpan jumlah pendaftar sebelum pengecekanthis.capacity = 5— namanya tanpa_, jadi memanggil set capacity
valuebernilai 5,this.reservedbernilai 125 < 12, jadithrow— tidak ada yang masuk ke_capacity
this.capacity = 5 memanggil set capacity. Exception-nya keluar dari constructor dan sampai ke try.Kalau this.reserved = reserved dipindah ke bawah this.capacity = capacity, this.reserved masih undefined saat setter berjalan. Dalam perbandingan angka, undefined diperlakukan sebagai NaN, dan 5 < NaN bernilai false, jadi instance-nya tetap dibuat dengan kapasitas 5.
Menolak Assignment — Property yang Hanya Punya Getter
Sisa kursi ditentukan oleh kapasitas dan jumlah pendaftar. Kalau kode di halaman bisa menulis seminar.remainingSeats = 100, halaman akan menampilkan sisa 100 kursi padahal kapasitasnya 30 dan pendaftarnya 12, sehingga ketiga value itu tidak lagi cocok.
Property yang hanya punya getter tanpa setter dengan nama yang sama bersifat read-only (bisa dibaca, tapi tidak bisa di-assign). Di dalam body class, dan di strict mode (mode eksekusi yang mengubah sebagian kesalahan menjadi exception) seperti di runtime ini, baris yang meng-assign ke property itu berhenti dengan TypeError. Di luar itu, assignment-nya diabaikan tanpa pemberitahuan.
class Seminar {
constructor(capacity, reserved) {
this.capacity = capacity;
this.reserved = reserved;
}
get remainingSeats() { return this.capacity - this.reserved; } // Tanpa setter
}
const seminar = new Seminar(30, 12);
try {
seminar.remainingSeats = 100; // Assign ke nama yang tidak punya set
} catch (error) {
console.log(error.name); // TypeError
}
console.log(seminar.remainingSeats); // 18 (sama seperti sebelum assignment)
// Untuk mengubah sisa kursi, ubah jumlah pendaftar yang menjadi dasarnya
seminar.reserved = 20;
console.log(seminar.remainingSeats); // 10
Baris bawah berhenti karena nama yang hanya punya getter tidak punya tempat untuk menampung value yang di-assign, dan tidak ada key baru yang dibuat di instance. Tabel di bawah merangkum cara menulis yang dipakai di Seminar pada artikel ini, beserta method sebagai pembanding.
| Cara menulis | Cara memakainya | Cocok untuk |
|---|---|---|
| Property biasa (reserved) | seminar.reserved = 20 langsung | Value yang tak perlu dicek |
| Hanya getter (remainingSeats) | Dibaca: seminar.remainingSeats | Value hasil hitungan |
| Getter dan setter (capacity) | seminar.capacity = 40 dicek dulu | Value yang dicek tiap assign |
| Method (misal reserve(count)) | Dipanggil pakai () dan argument | Hasil tergantung argument |
Cek Pemahaman
Jawab setiap pertanyaan satu per satu.
Soal 2Kalau set capacity berisi this.capacity = value; lalu kamu meng-assign 40, apa yang terjadi?
Soal 3Apa yang terjadi kalau kamu meng-assign 100 ke seminar.remainingSeats, yang hanya punya getter?