Kelas

Sintaks class, constructor, dan metode sebagai pemanis di atas prototype.

Daftar isi

Sintaks class mengumpulkan data dan perilaku yang dibagikan ke banyak object dalam satu tulisan yang rapi. Di balik layar, kelas bukan sistem baru, melainkan pembungkus mekanisme prototype, sehingga istilahnya sering disebut pemanis sintaksis (syntactic sugar), tulisan yang lebih nyaman di atas perilaku yang sudah ada. Topik ini membangun kelas pertama dengan constructor dan metode instansi, membuktikan hubungannya dengan prototype lewat pemeriksaan langsung, menunjukkan kelas sebagai ekspresi, dan menutup dengan field instansi beserta dua kesalahan umum pemakaiannya. Semua contoh berupa berkas JavaScript utuh yang dijalankan dengan Node.js.

Sintaks class dan constructor#

Kelas dideklarasikan dengan kata class, tubuhnya memuat constructor untuk pengisian data awal dan metode untuk perilakunya. Object baru lahir lewat new, dan setiap object yang dihasilkan disebut instansi dari kelasnya. Berkas berikut mendefinisikan kelas Anggota untuk katalog perpustakaan, lalu membuat dua instansinya dengan data yang berbeda.

js kelas-dasar.js
// Kelas mengumpulkan data dan perilaku untuk membuat banyak object.

class Anggota {
  constructor(nama, nomor) {
    this.nama = nama;
    this.nomor = nomor;
    this.pinjaman = [];
  }

  pinjam(judul) {
    this.pinjaman.push(judul);
    return this.pinjaman.length;
  }
}

const anggotaA = new Anggota("Citra", "P-1024");
const anggotaB = new Anggota("Dewi", "P-1025");

anggotaA.pinjam("Kamus Bahasa Indonesia");
anggotaA.pinjam("Ensiklopedia Sains");
anggotaB.pinjam("Atlas Dunia");

console.log(anggotaA.nomor, anggotaA.nama);
console.log(anggotaA.pinjaman);
console.log(anggotaB.pinjaman);
text Keluaran
P-1024 Citra
[ 'Kamus Bahasa Indonesia', 'Ensiklopedia Sains' ]
[ 'Atlas Dunia' ]

Kata new menjalankan empat langkah berurutan, membuat object kosong, memasang prototipenya dari Anggota.prototype, menjalankan constructor dengan this menunjuk object baru itu, lalu mengembalikan object tersebut. Data nama, nomor, dan pinjaman ditempel di dalam constructor sehingga setiap object membawa salinannya sendiri, terlihat dari daftar pinjaman yang berbeda pada kedua anggota. Metode pinjam mengubah data lewat this, sehingga pemanggilan lewat object mana pun mengubah data object itu.

Bukti: metode kelas tinggal di prototype#

Klaim bahwa kelas berdiri di atas prototype dapat diuji langsung tanpa alat tambahan. Fungsi typeof memeriksa jenis kelas, Object.getPrototypeOf membaca prototipe sebuah instansi, dan Object.getOwnPropertyNames mendaftar properti yang dimiliki prototype kelas. Berkas berikut menjalankan ketiganya pada kelas yang sama.

js bukti-prototipe.js
// Metode kelas tercatat pada prototype-nya, bukan pada setiap instansi.

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

  sapa() {
    return "Selamat datang, " + this.nama;
  }
}

const anggota = new Anggota("Citra");

console.log(typeof Anggota);
console.log(Object.getPrototypeOf(anggota) === Anggota.prototype);
console.log(Object.getOwnPropertyNames(Anggota.prototype));
console.log(anggota.sapa === Anggota.prototype.sapa);
console.log(anggota.sapa());
text Keluaran
function
true
[ 'constructor', 'sapa' ]
true
Selamat datang, Citra

Nilai typeof Anggota adalah function, karena kelas pada dasarnya adalah fungsi khusus. Prototipe anggota memang Anggota.prototype, dan daftar properti pada prototype itu hanya constructor dan sapa, bukti bahwa metode kelas dicatat di sana. Karena metode sapa diambil dari prototype, perbandingannya dengan Anggota.prototype.sapa menghasilkan true, dan satu salinan metode itu melayani semua instansi kelas. Pemanis sintaksisnya terasa pada tulisan, sedangkan mesinnya tetap delegasi prototype.

Kelas adalah ekspresi#

Seperti fungsi, kelas dapat ditulis sebagai deklarasi maupun ekspresi, yaitu kelas yang ditulis di tengah ekspresi dan dianggap satu nilai. KelasCadangan dihasilkan dari ekspresi class tanpa nama, disimpan ke variabel, dan dipakai seperti kelas biasa. Bentuk ini membuka kemungkinan kelas dibuat oleh fungsi. Fungsi buatKelas mengembalikan kelas baru setiap kali dipanggil, dengan perilaku yang dibentuk dari argumennya. Kelas adalah nilai, dan nilai bisa dioper, disimpan, serta dikembalikan.

js kelas-ekspresi.js
// Kelas dapat ditulis sebagai ekspresi dan berperilaku seperti fungsi.

const KelasCadangan = class {
  sapa() {
    return "kelas dari ekspresi";
  }
};

const cadangan = new KelasCadangan();
console.log(typeof KelasCadangan);
console.log(cadangan.sapa());

function buatKelas(sapaan) {
  return class {
    sapa() {
      return sapaan;
    }
  };
}

const KelasBuatan = buatKelas("kelas dari pabrik");
console.log(new KelasBuatan().sapa());
text Keluaran
function
kelas dari ekspresi
kelas dari pabrik

Keluarannya menegaskan sifat kelas sebagai nilai, typeof KelasCadangan tetap function meski kelasnya lahir dari ekspresi tanpa nama. Pemakaian yang lazim adalah memilih kelas sesuai kondisi, misalnya pabrik di atas yang menghasilkan kelas dengan sapaan berbeda untuk tiap panggilannya, tanpa menulis deklarasi terpisah. Ekspresi kelas juga boleh diberi nama internal untuk pemanggilan dirinya sendiri, tetapi kebutuhan itu jarang muncul pada kode harian. Yang penting diingat, bentuk ekspresi mengikuti aturan nilai pada umumnya, sehingga kelas bisa berpindah tempat seperti array atau fungsi.

Field instansi#

Field dideklarasikan dengan dua cara, ditulis langsung di tubuh kelas seperti batasAtas, atau ditempel di dalam constructor seperti id dan pembaruan. Keduanya menghasilkan properti milik masing-masing object, dibuktikan oleh Object.hasOwn yang bernilai true untuk field dan false untuk metode. Perhitungan pembaruan pada setiap sensor berjalan sendiri-sendiri. Sensor A mencatat dua kali, sementara sensor B satu kali. Pembagian kerjanya tegas, dengan field menampung data per object dan metode menampung perilaku bersama.

js field-instansi.js
// Field instansi lahir baru pada setiap object, metode dibagi lewat prototype.

class SensorSuhu {
  batasAtas = 30;

  constructor(id) {
    this.id = id;
    this.pembaruan = 0;
  }

  catat(nilai) {
    this.pembaruan += 1;
    return this.id + ": " + nilai + " derajat, catatan ke-" + this.pembaruan;
  }
}

const sensorA = new SensorSuhu("S-1");
const sensorB = new SensorSuhu("S-2");

console.log(sensorA.catat(24));
console.log(sensorA.catat(26));
console.log(sensorB.catat(28));
console.log(Object.hasOwn(sensorA, "batasAtas"));
console.log(Object.hasOwn(sensorA, "catat"));
text Keluaran
S-1: 24 derajat, catatan ke-1
S-1: 26 derajat, catatan ke-2
S-2: 28 derajat, catatan ke-1
true
false

Kesalahan umum#

Dua kesalahan paling sering muncul pada awal memakai kelas. Pertama, kelas dipanggil tanpa new, dan JavaScript menolaknya dengan error alih-alih diam, berbeda dari fungsi biasa yang bisa dijalankan lepas. Kedua, kelas dipakai sebelum deklarasinya, sedangkan deklarasi kelas tidak diangkat seperti deklarasi fungsi. Keduanya terlihat pada berkas berikut.

js kesalahan-kelas.js
// Kelas wajib dipanggil dengan new dan tidak terangkat sebelum deklarasinya.

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

try {
  Anggota("Citra");
} catch (error) {
  console.log(error.name + ": " + error.message);
}

try {
  const anggota = new AnggotaDua("Citra");
  console.log(anggota.nama);
} catch (error) {
  console.log(error.name + ": " + error.message);
}

class AnggotaDua {
  constructor(nama) {
    this.nama = nama;
  }
}
text Keluaran
TypeError: Class constructor Anggota cannot be invoked without 'new'
ReferenceError: Cannot access 'AnggotaDua' before initialization

Pemanggilan Anggota("Citra") tanpa new memunculkan error TypeError yang pesannya menyebut new secara eksplisit. Pemanggilan new AnggotaDua("Citra") yang tertulis sebelum deklarasinya memunculkan ReferenceError karena kelas itu belum terinisialisasi pada saat kode tersebut berjalan. Perbaikan keduanya segera terlihat dari pesannya. Tambahkan new pada pemanggilan kelas dan pindahkan pemakaiannya ke bawah deklarasi.

Ringkasan#

  • class mendefinisikan cetakan object dengan constructor untuk data awal dan metode untuk perilaku bersama.
  • new membuat object baru, memasang prototipenya, menjalankan constructor dengan this menunjuk object itu, lalu mengembalikannya.
  • Metode kelas tercatat pada Anggota.prototype dan dibagi satu salinan untuk semua instansi, bukti bahwa kelas berdiri di atas prototype.
  • Kelas dapat ditulis sebagai ekspresi yang dianggap nilai, dan field instansi lahir baru pada setiap object.
  • Kelas wajib dipanggil dengan new dan tidak terangkat sebelum deklarasinya.

Referensi#