Belajar dengan membaca secara berurutan

constructor dan Class Field — Menentukan Value Awal

Constructor dan class field menentukan value awal instance. Membahas penyimpanan argument, urutan pengisian field, value bawaan, dan penolakan value yang tidak valid.

Tiket layanan pelanggan punya value yang berbeda di setiap tiket, seperti judulnya, dan value awal yang sama untuk semua tiket, seperti status "Baru". Kalau class-nya ditulis asal-asalan, value yang dikosongkan atau value yang tidak valid ikut tersimpan di instance.

Artikel ini membahas constructor, yang menerima value saat instance dibuat, dan class field, yang mendeklarasikan value awal yang sudah pasti.

Merapikan Argument Sebelum Disimpan — Body constructor

Judul tiket yang dikirim lewat formulir layanan pelanggan kadang punya spasi berlebih di awal atau di akhir. Kalau string tampilan seperti "Budi: Gagal login" baru disusun setelah instance dibuat, setiap halaman yang menampilkannya butuh kode trim dan penyusun string-nya sendiri.

Di body constructor, argument tidak harus disimpan apa adanya. Kamu bisa menyimpan versi yang sudah dirapikan, seperti this.title = title.trim(), atau value yang disusun dari beberapa argument. Setiap halaman tinggal membaca property instance dan langsung mendapat value yang sudah rapi.

class Ticket {
  constructor(title, customerName) {
    // Rapikan argument sebelum menyimpannya di this
    this.title = title.trim();
    this.customerName = customerName;

    // Susun value tampilan dari this, setelah dirapikan
    this.label = `${this.customerName}: ${this.title}`;
    // Kalau ditulis `${customerName}: ${title}`, spasi di judul ikut terbawa
  }
}

// Berikan judul yang punya spasi di awal dan akhir
const ticket = new Ticket("  Gagal login ", "Budi");
console.log(ticket.title);    // Gagal login
console.log(ticket.label);    // Budi: Gagal login
Dari Value Mana label Disusun
Disusun dariargument titletitle masihberspasiSpasinya ikutdisisipkanAda spasi lebihsetelah "Budi:"Disusun darithis.titlethis.titlesudah di-trimJudul yang rapidisisipkanBudi:Gagal login
Kedua baris sama-sama tidak menimbulkan error; bedanya hanya terlihat di tampilan. Untuk memakai value yang sudah dirapikan, baca lagi dari this setelah disimpan.

Baris atas membaca argument title, sedangkan baris bawah membaca this.title setelah trim. Kalau baris label dipindah ke awal constructor, this.title maupun this.customerName belum di-assign, jadi label menjadi undefined: undefined.

Buat data reservasi dari value di formulir reservasi. selectedRoom, selectedStart, dan selectedHours sudah dideklarasikan.

① Definisikan Reservation agar setiap instance menyimpan nama ruangan, jam mulai, dan durasi.

② Di dalam constructor, simpan juga jam selesai sebagai endHour.

③ Buat booking dengan memberikan ketiga value itu.

④ Tampilkan dalam format "Ruangan: X.00-X.00 (X jam)".

(Kalau berjalan dengan benar, penjelasan akan muncul.)

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Menuliskan Value Awal yang Sudah Pasti — Class Field

Setiap tiket yang masuk dimulai dengan status "Baru" dan nol komentar. Kalau value awal seperti ini, yang tidak ada hubungannya dengan argument, ditulis di constructor sebagai this.status = "Baru";, baris-baris itu bercampur dengan baris yang menyimpan argument, dan kamu harus membaca seluruh body untuk tahu apa saja yang dimiliki instance.

Class field (property yang dideklarasikan di dalam kurung kurawal class tapi di luar constructor dan method, lalu ditambahkan ke instance setiap kali new dipanggil) cukup ditulis sebagai nama dan value awal, tanpa this, seperti status = "Baru";. Untuk membacanya dari body constructor atau dari method, tulis this.status, sama seperti property lainnya.

class Ticket {
  // Value awal yang tidak bergantung pada argument ditulis sebagai field
  status = "Baru";
  comments = [];

  constructor(title) {
    this.title = title;
    this.summary = `[${this.status}] ${title}`;   // Value field sudah bisa dibaca di sini
  }
}

const first = new Ticket("Gagal login");
const second = new Ticket("Invoice belum diterima");
console.log(first.summary);                // [Baru] Gagal login

// comments adalah array terpisah yang dibuat setiap kali new dipanggil
first.comments.push("Pelanggan diminta me-restart perangkat");
console.log(first.comments.length);        // 1
console.log(second.comments.length);       // 0
Urutan Langkah di Dalam new Ticket
new Ticket("Gagal login")① Tambahkan fielddari atas ke bawah② Jalankan body,baca this.status③ Instancemasuk ke firstInstancemasih kosongstatus: "Baru"comments: []title dan summaryditambahkanSekarang punya4 property
Di dalam new, field ditambahkan lebih dulu, baru kemudian body constructor berjalan. Body sudah bisa membaca value field.

Langkah ① diulang setiap kali new dipanggil, jadi comments = [] menjadi array terpisah untuk setiap instance, dan komentar yang ditambahkan ke first tidak ikut masuk ke second. Karena itulah second.comments.length tetap 0.

Menulis this. di Field Melempar SyntaxError

Kalau kamu menulis this.status = "Baru"; di tempat field (di luar constructor), muncul SyntaxError: Unexpected token '.' dan tidak ada satu baris pun yang berjalan. Menambahkan let atau const juga melempar SyntaxError. Field cukup berisi nama dan value awal.

Buat data pengiriman untuk setiap tujuan. destinations sudah dideklarasikan.

① Definisikan Shipment yang menerima tujuan, dengan value awal ongkos kirim 600 dan status "Diterima".

② Di dalam constructor, ubah ongkos kirim menjadi 1500, tapi hanya kalau tujuannya "Okinawa".

③ Buat Shipment untuk setiap tujuan dan masukkan ke array shipments.

④ Tampilkan masing-masing dalam format "Tujuan: status / Ongkos kirim X yen".

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Menentukan Value Saat Argument Dikosongkan — Default Parameter

Sebagian besar tiket berprioritas "Normal", dan kamu hanya ingin memberikan "Mendesak" kalau ada hal yang perlu segera ditangani. Kalau kamu menulis field priority = "Normal"; lalu juga menambahkan this.priority = priority; di body, tiket yang dibuat tanpa prioritas tidak akan bernilai "Normal".

Default parameter (cara menentukan value yang dipakai kalau argument tidak dioper), yang sudah kamu lihat di artikel tentang default parameter dan rest parameter, juga bisa dipakai di constructor: tulis priority = "Normal" di daftar parameter. Argument yang dikosongkan atau bernilai undefined diganti dengan value bawaan sebelum body berjalan, jadi this.priority = priority menerima "Normal".

// Value bawaan di field, ditambah assign argument di body
class DraftTicket {
  priority = "Normal";
  constructor(title, priority) {
    this.title = title;
    this.priority = priority;   // priority di kanan adalah argument (undefined kalau dikosongkan)
  }
}
console.log(new DraftTicket("Gagal login").priority);                    // undefined

// Untuk value yang bisa diubah lewat argument, tulis value bawaan di default parameter
class Ticket {
  constructor(title, priority = "Normal") {
    this.title = title;
    this.priority = priority;
  }
}
console.log(new Ticket("Gagal login").priority);                         // Normal
console.log(new Ticket("Invoice belum diterima", "Mendesak").priority);   // Mendesak
Bagaimana "Normal" dari Field Hilang
new DraftTicket("Gagal login")① Tambahkanfield② Body assignthis.title③ Body assignthis.priorityArgument prioritybernilai undefinedthis.prioritybernilai "Normal"this.prioritymasih "Normal"this.priorityjadi undefined
"Normal" dari field diisi sebelum body, lalu assignment di body menimpanya dengan undefined dari argument. Yang tersisa di akhir adalah value yang di-assign di body.

Tulis value yang bisa diubah lewat argument di default parameter, dan value yang tidak bergantung pada argument di field. Untuk value yang bergantung pada kondisi argument, seperti ongkos kirim di Latihan 2, pakai if di body untuk mengubah value awal field. Tabel di bawah menunjukkan value yang tersisa di priority untuk setiap cara, dengan dan tanpa "Mendesak", termasuk cara yang tidak meng-assign-nya di body.

CaraHanya judulDengan "Mendesak"
Hanya field (tanpa assign di body)NormalNormal (diabaikan)
Field + this.priority = priorityundefinedMendesak
Default parameter priority = "Normal"NormalMendesak

Menolak Value yang Tidak Valid — throw di constructor

Kalau sampai ada tiket dengan judul kosong, atau dengan prioritas di luar value yang sudah disepakati seperti "Tinggi", daftar tiket menampilkan baris kosong, dan tiket itu tidak ikut terhitung saat kamu menghitung tiket "Mendesak". Walaupun kamu menulis function terpisah untuk memeriksa tiket setelah dibuat, halaman yang lupa memanggilnya tetap memakai instance yang tidak valid.

Untuk validasi saat pembuatan (memeriksa, pada saat instance dibuat, bahwa value yang diterima memenuhi aturan), tulis if di dalam constructor dan lempar exception dengan throw new Error(...) kalau value-nya tidak lolos. Begitu exception dilempar, ekspresi new tidak mengembalikan instance.

class Ticket {
  constructor(title, priority = "Normal") {
    // Tolak value yang tidak valid dengan exception sebelum masuk ke this
    if (title.trim() === "") {
      throw new Error("Judul kosong");
    }
    if (priority !== "Normal" && priority !== "Mendesak") {
      throw new Error(`Prioritas harus Normal atau Mendesak: ${priority}`);
    }
    this.title = title.trim();
    this.priority = priority;
  }
}

try {
  const ticket = new Ticket("Gagal login", "Tinggi");
  console.log(ticket.title);    // Baris ini tidak pernah berjalan
} catch (error) {
  console.log(error.message);   // Prioritas harus Normal atau Mendesak: Tinggi
}
Ke Mana throw di Dalam new Berakhir
Di dalam try (new dipanggil di sini)
  • const ticket = new Ticket(...) — sisi kanan melempar exception, jadi ticket tidak berisi apa pun
  • console.log(ticket.title) — tidak pernah berjalan
Body constructor yang dipanggil
  • Cek judul — tidak kosong, jadi lolos
  • Cek prioritas — isinya "Tinggi", jadi throw dijalankan
  • this.title = ... — mulai dari sini ke bawah tidak berjalan
Di dalam catch (error)
  • error.message — "Prioritas harus Normal atau Mendesak: Tinggi"
Exception keluar dari ekspresi new, melewati sisa try, lalu sampai di catch. Instance yang tidak valid tidak pernah masuk ke variabel mana pun.

Dengan pengecekan di constructor, tidak ada tiket tidak valid yang bisa lolos, di mana pun new Ticket(...) dipanggil. Kalau value yang ditolak kamu sertakan di pesan exception, sisi catch juga bisa menampilkan value mana yang tidak valid.

Assignment Setelah Instance Dibuat Tidak Diperiksa

Pengecekan di constructor hanya berjalan saat new. Kalau kamu meng-assign ticket.priority = "Tinggi"; setelah tiket dibuat, tidak ada error, dan value-nya langsung tertimpa. Cara memeriksa value di setiap assignment dibahas di artikel tentang getter dan setter.

Terima hanya baris pesanan yang memenuhi aturan. requests dan acceptedLines sudah dideklarasikan.

① Definisikan OrderLine yang menerima nama produk dan jumlah (1 kalau jumlahnya tidak diberikan).

② Lempar exception dengan pesan "Nama produk kosong" kalau nama produknya kosong, atau "Jumlah tidak valid: X" kalau jumlahnya bukan bilangan bulat positif.

③ Ubah setiap request menjadi OrderLine. Kalau berhasil, masukkan ke acceptedLines dan tampilkan "Diterima: nama x jumlah"; kalau gagal, tampilkan "Ditolak: pesan exception".

④ Tampilkan jumlah baris yang diterima dalam format "Total diterima: X".

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Di constructor sebuah class yang punya status = "Baru";, apa yang terjadi kalau kamu membaca this.status?

Soal 2Sebuah class hanya punya field priority = "Normal"; dan tidak meng-assign-nya di body. Apa yang terjadi kalau kamu memberikan "Mendesak"?

Soal 3Di dalam try, constructor melempar exception saat const ticket = new Ticket(""). Apa yang terjadi?