Belajar dengan membaca secara berurutan

Inheritance — extends dan super

extends dipakai untuk membuat class baru di atas class yang sudah ada. Membahas super() di constructor, override, dan super.methodName().

Misalnya sebuah toko buku online butuh class untuk e-book, di samping class Book untuk buku cetak. Bedanya hanya dua: e-book bisa diunduh dan tidak kena ongkos kirim. Tapi dengan cara yang kamu tahu sejauh ini, bagian yang mengurus judul dan harga pun harus ditulis ulang.

Artikel ini membahas extends, yang membangun class baru di atas class yang sudah ada, dan super, yang memanggil kode di class yang diwarisi itu.

Memakai Ulang Kode Tanpa Menyalinnya — extends

E-book juga butuh constructor yang menerima judul dan harga, serta method describe yang mengembalikan "judul: harga yen". Kalau isi Book kamu salin ke class e-book yang baru, baris yang sama ada di dua tempat. Kalau nanti format tampilannya diubah dan salah satu salinan lupa diperbarui, tampilan di tiap layar jadi berbeda.

Inheritance (mekanisme agar class lain bisa memakai constructor dan method dari class yang sudah ada) ditulis sebagai class EBook extends Book. Book disebut parent class, dan EBook disebut child class.

extends Error yang kamu tulis di artikel throw dan custom error juga termasuk inheritance.

class Book {
  constructor(title, price) {
    this.title = title;
    this.price = price;
  }
  describe() { return `${this.title}: ${this.price} yen`; }
}

// Mewarisi Book dan menambahkan method yang hanya dimiliki e-book
class EBook extends Book {
  download() { return `Mengunduh ${this.title}`; }
}

const ebook = new EBook("Statistika Dasar", 2200);   // Argument-nya diteruskan ke constructor Book
console.log(ebook.describe());                      // Statistika Dasar: 2200 yen
console.log(ebook.download());                      // Mengunduh Statistika Dasar

const book = new Book("Statistika Dasar", 2640);
console.log(typeof book.download);                  // undefined (parent class tidak punya method milik child class)
Pohon Inheritance dari Book ke EBook
class Bookconstructor,describebook hanya bisamemanggil describeclass EBookextends BookEBook hanyamendefinisikandownloadInstance darinew EBook(...)Bisa memanggildescribe dandownload
EBook hanya mendefinisikan download, tapi describe juga bisa dipanggil. Sebaliknya, book tidak bisa memanggil download.

Di dalam ebook.describe(), this adalah ebook, jadi this.title yang ditulis di Book membaca judul yang kamu berikan ke new EBook. Yang memasukkan judul itu ke ebook pun adalah constructor milik Book, yang menerima argument-nya.

Tampilkan catatan untuk setiap password yang di-reset oleh admin. User dan targets sudah dideklarasikan.

① Definisikan AdminUser yang mewarisi User.

② Tambahkan resetPassword, yang mengembalikan catatan berisi deskripsi admin itu sendiri dan nama user yang password-nya di-reset.

③ Buat seorang admin, lalu tampilkan catatan untuk semua orang di targets.

④ Tampilkan apakah admin itu juga instance dari User.

(Kalau berjalan dengan benar, penjelasan akan muncul.)

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Menambah Value di Child Class — super() dan constructor

Sekarang e-book juga perlu menyimpan ukuran file, fileSize, selain judul dan harga. Untuk menerima ukuran file, EBook butuh constructor sendiri. Tapi begitu kamu menulisnya, constructor milik Book tidak lagi dipanggil otomatis, dan kalau dibiarkan begitu saja, new akan berhenti dengan ReferenceError.

super() (cara memanggil constructor parent class dari dalam constructor child class) menerima argument yang diteruskan ke parent, seperti super(title, price);.

Di child class, this disiapkan oleh constructor parent selama super() berjalan, jadi panggil super() sebelum baris mana pun yang memakai this.

class Book {
  constructor(title, price) {
    this.title = title;
    this.price = price;
  }
}

class EBook extends Book {
  constructor(title, price, fileSize) {
    // Kalau this.fileSize = fileSize; ditulis sebelum baris ini, new melempar ReferenceError
    super(title, price);          // Constructor Book mengisi title dan price
    this.fileSize = fileSize;     // Setelah itu, tambahkan value yang hanya dimiliki EBook
  }
}

const ebook = new EBook("Statistika Dasar", 2200, 12);
console.log(ebook.title);                      // Statistika Dasar
console.log(ebook.fileSize);                   // 12
console.log(Object.keys(ebook).join(", "));    // title, price, fileSize
Apakah super() Dipanggil Sebelum this?
this.fileSizeditulis duluansuper() belumdipanggilBerhenti di barisyang memakai thisReferenceErrorsaat newsuper(title,price) ditulisduluanBook mengisititle dan pricethis.fileSizediisi 12ebook punyaketiga value
Di baris atas, memakai this sebelum super() menimbulkan error, dan instance tidak terbentuk. this baru bisa dipakai setelah super() selesai.

Key-nya muncul dengan urutan title, price, fileSize karena Book lebih dulu mengisi value-nya di dalam super(). Baris atas gagal dengan ReferenceError: Must call super constructor in derived class before accessing 'this' …, dan "derived class" di sini maksudnya child class.

Child Class Tidak Bisa Membaca Field # Milik Parent

Kalau Book punya private field #price, super() tetap mengisi value-nya, tapi menulis this.#price di body EBook melempar SyntaxError. Nama # hanya bisa dipakai di dalam class yang mendeklarasikannya, jadi child class harus membacanya lewat getter yang didefinisikan di parent.

Tampilkan hak akses tiap admin di halaman admin. User dan adminInput sudah dideklarasikan.

① Definisikan AdminUser, yang mewarisi User dan menerima nama, email, serta array hak akses.

② Isi nama dan email lewat constructor User.

③ Buat admin dari adminInput, lalu tampilkan namanya beserta rincian hak aksesnya.

④ Tampilkan key-nya sesuai urutan, lalu cek di posisi mana status yang didefinisikan di User muncul.

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Mengubah Ongkos Kirim di Child Class — Override

Kalau kamu menambahkan method shippingFee ke Book, e-book juga kena ongkos kirim yang sama dengan buku cetak. Kamu bisa saja membuatnya 0 yen khusus untuk e-book dengan memeriksa jenis buku memakai if di dalam Book, tapi percabangan di parent class akan bertambah setiap kali ada child class baru.

Override (menulis method di child class dengan nama yang sama seperti di parent, sehingga versi child yang berjalan untuk instance child) cukup dilakukan dengan menulis ulang shippingFee di body EBook. Saat method dipanggil, JavaScript mencari namanya mulai dari class yang membuat instance itu, lalu lanjut ke parent class kalau tidak ditemukan.

class Book {
  constructor(title, price) {
    this.title = title;
    this.price = price;
  }
  describe() { return `${this.title}: ${this.price} yen`; }
  shippingFee() { return this.price >= 3000 ? 0 : 500; }   // Gratis ongkir mulai 3000 yen
}

class EBook extends Book {
  shippingFee() { return 0; }   // Di-override dengan nama yang sama (tidak ada barang yang dikirim)
}

const book = new Book("Statistika Dasar", 2640);
const ebook = new EBook("Statistika Dasar", 2200);
console.log(book.shippingFee());    // 500
console.log(ebook.shippingFee());   // 0 (shippingFee milik EBook yang berjalan)
console.log(ebook.describe());      // Statistika Dasar: 2200 yen (describe milik Book yang berjalan)
Urutan Pencarian Method yang Dipanggil
EBook hanyameng-overrideshippingFeebook.shippingFee()ebook.shippingFee()ebook.describe()Mulai di Book,ditemukan di BookMulai di EBook,ditemukan di EBookTak ada di EBook,ditemukan di Book2640 kurang dari3000, jadi 5000, tanpamemeriksa BookStatistika Dasar:2200 yen
Pencarian dimulai dari class yang membuat instance. Kalau sudah ditemukan di EBook, method bernama sama di Book tidak berjalan.

shippingFee milik EBook tidak memakai perhitungan Book, jadi walaupun aturan ongkos kirim di Book diubah, e-book tetap 0 yen. Bagian berikutnya membahas cara memanggil kode parent lalu menambahkan bagian yang berbeda saja.

Di forum internal kantor, tentukan apakah tombol edit ditampilkan untuk setiap postingan. User dan posts sudah dideklarasikan.

① Definisikan AdminUser yang mewarisi User, lalu override pengecekannya agar admin bisa mengedit postingan apa pun.

② Buat user biasa "Budi" dan admin "Siti".

③ Untuk setiap postingan, tampilkan apakah masing-masing bisa mengeditnya, dalam bentuk "Postingan N: Budi X / Siti Y".

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Menambahkan ke Kode Parent — super.methodName()

Berikutnya, kamu ingin deskripsi e-book diakhiri dengan "(e-book, 12 MB)". Kalau kamu meng-override describe di EBook dan ikut menyalin kode yang menyusun "judul: harga yen", begitu format tampilan Book diubah, deskripsi e-book akan tetap memakai format lama.

Dengan super.methodName() (cara memanggil method yang didefinisikan di parent class dari dalam method child class), super.describe() mengembalikan return value describe milik Book. Child class cukup menambahkan detail e-book ke string itu.

class Book {
  constructor(title, price) {
    this.title = title;
    this.price = price;
  }
  describe() { return `${this.title}: ${this.price} yen`; }
}

class EBook extends Book {
  constructor(title, price, fileSize) {
    super(title, price);
    this.fileSize = fileSize;
  }

  // Menambahkan detail e-book ke return value describe milik Book
  describe() { return `${super.describe()} (e-book, ${this.fileSize} MB)`; }
}

const ebook = new EBook("Statistika Dasar", 2200, 12);
console.log(ebook.describe());   // Statistika Dasar: 2200 yen (e-book, 12 MB)
Urutan yang Berjalan di Dalam ebook.describe()
ebook.describe()mulai berjalanthis adalah ebook(fileSize 12)super.describe()menjalankandescribe Bookthis tetap ebook:Statistika Dasar:2200 yenMenambahkan(e-book, 12 MB)ke return valueMengembalikanStatistika Dasar:2200 yen(e-book, 12 MB)
describe milik Book berjalan di tengah describe milik EBook, lalu kembali. Kode yang menyusun judul dan harga hanya ada di Book.

super.describe() adalah ekspresi yang menghasilkan return value Book, jadi kalau kamu ingin detail e-book ada di depan, cukup pindahkan posisinya di dalam template literal. Tabel di bawah merangkum sintaks inheritance yang dipakai di artikel ini dan apa yang berjalan untuk masing-masing.

SintaksTempat menulisYang berjalan
class EBook extends BookDeklarasi classMewarisi constructor dan method Book
super(title, price)Constructor child, sebelum thisConstructor Book
Method bernama sama dengan parentBody child classVersi EBook, untuk instance EBook
super.describe()Di dalam method childdescribe milik Book

Tanpa super, Method Terus Memanggil Dirinya Sendiri

Kalau kamu menulis this.describe(), bukan super.describe(), di describe milik child class, method itu terus memanggil dirinya sendiri sampai berhenti dengan RangeError: Maximum call stack size exceeded. Untuk memanggil kode parent dari method yang sudah di-override, pakai super..

Di tool internal kantor, terapkan aturan password yang lebih ketat khusus untuk admin. User, AdminUser, admin, member, dan passwords sudah dideklarasikan.

① Tambahkan checkPassword ke AdminUser. Method ini menjalankan pengecekan User lebih dulu, lalu kalau lolos, juga memeriksa apakah panjangnya minimal 12 karakter.

② Periksa passwords secara berurutan sebagai admin, lalu tampilkan hasilnya.

③ Periksa password kedua sebagai user biasa, lalu tampilkan hasilnya.

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Apa yang terjadi kalau kamu memanggil new pada EBook yang meng-assign this.fileSize sebelum super()?

Soal 2Kalau Book dan EBook sama-sama punya method shippingFee, mana yang berjalan saat kamu memanggil ebook.shippingFee()?

Soal 3Di dalam describe milik EBook, bagaimana cara mendapatkan return value describe milik Book?