Belajar dengan membaca secara berurutan

Instance Member dan static — Value dan Method Milik Class

static menaruh value dan method di class itu sendiri. Membahas counter dengan static field, factory method yang membuat instance dari JSON, konstanta bersama, dan kapan memakai instance member.

Untuk memberi nomor 1, 2, 3 pada paket sesuai urutan pembuatannya, kamu perlu mencatat berapa paket yang sudah dibuat. Penerima setiap paket berbeda, tapi jumlah paket yang sudah dibuat dan batas berat cukup ada satu, dipakai bersama oleh semua paket.

Artikel ini membahas static, yang menaruh value dan method di class itu sendiri, bukan di instance-nya.

Menghitung Jumlah Paket — static Field

Kalau kamu menulis class field count = 0;, menambahnya dengan this.count += 1 di constructor, lalu memakainya sebagai nomor paket, semua paket mendapat nomor 1, karena field diisi ulang dari 0 setiap kali new dipanggil.

Static field (property yang dideklarasikan di dalam class dengan keyword static; hanya ada satu, di class itu sendiri) dibaca dan ditulis lewat nama class, seperti Parcel.count.

Sebaliknya, property yang dimiliki setiap instance, seperti this.number, dan method yang ditulis tanpa static disebut instance member.

class Parcel {
  // Jumlah paket yang sudah dibuat, disimpan sekali di class
  static count = 0;

  constructor(recipient) {
    Parcel.count += 1;               // Tambah count milik class sebanyak satu
    this.number = Parcel.count;      // Pakai count saat ini sebagai nomor paket
    this.recipient = recipient;
  }
}

// Buat dua paket
const first = new Parcel("Budi");
const second = new Parcel("Siti");

console.log(first.number, second.number);   // 1 2
console.log(Parcel.count);                  // 2
console.log(first.count);                   // undefined
Tempat count dan Nomor Paket Disimpan
Parcel (class itu sendiri)
  • static count — 1 setelah new pertama, 2 setelah new kedua
  • Dibaca dan ditulis sebagai Parcel.count
Instance yang dibuat dengan new
first
  • number — 1 (count saat dibuat)
  • recipient — "Budi"
  • Tidak ada countfirst.count bernilai undefined
second
  • number — 2 (count saat dibuat)
  • recipient — "Siti"
count hanya ada satu, di kotak class, dan tidak ada di kotak instance. Kalau dibaca dari instance, hasilnya undefined.

Setiap pemanggilan new menambah count yang sama di kotak class sebanyak satu, lalu menyalin value-nya saat itu ke number milik instance baru. Walaupun count kemudian naik menjadi 2, first.number tetap 1, yaitu value yang didapatnya saat dibuat.

Beri nomor pada jawaban survei sesuai urutan masuknya. answerTexts sudah dideklarasikan.

① Definisikan SurveyAnswer yang menerima teks jawaban. Setiap kali jawaban dibuat, tambah satu jumlah jawaban yang dipakai bersama oleh semua jawaban, lalu pakai sebagai nomor jawaban itu.

② Ubah ketiga teks menjadi instance SurveyAnswer dan masukkan ke answers.

③ Tampilkan semua jawaban dalam format "A-001 teks jawaban".

④ Tampilkan "Jumlah jawaban: X" dan "Nomor jawaban pertama: X".

(Kalau berjalan dengan benar, penjelasan akan muncul.)

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Membuat Paket dari JSON — static Method

Saat memuat paket yang sudah disimpan, yang kamu dapat adalah string JSON berisi penerima dan berat. Kalau setiap halaman yang memuat paket punya JSON.parse dan new Parcel(...) sendiri, perubahan nama key di JSON berarti semua halaman itu harus diperbaiki.

Masalahnya, saat membuat paket dari JSON, belum ada instance yang bisa dipakai untuk memanggil method. Static method (method yang didefinisikan dengan static dan dipanggil lewat nama class tanpa membuat instance) bisa dipanggil sebagai Parcel.fromJSON(text). Static method seperti fromJSON, yang membuat lalu mengembalikan instance, disebut factory method.

class Parcel {
  constructor(recipient, weightKg) {
    this.recipient = recipient;
    this.weightKg = weightKg;
  }

  label() {
    return `${this.recipient} (${this.weightKg} kg)`;
  }

  // Terima string JSON, lalu buat dan kembalikan instance Parcel
  static fromJSON(text) {
    const data = JSON.parse(text);
    return new Parcel(data.recipient, data.weightKg);
  }
}

const text = '{"recipient":"Budi","weightKg":2}';
const parcel = Parcel.fromJSON(text);        // Dipanggil lewat nama class
console.log(parcel.label());                 // Budi (2 kg)
Dari String JSON Menjadi Parcel
Parcel.fromJSON(text) dipanggilDiurai denganJSON.parse(text)Buat new Parcel(…)lalu kembalikantext hanyasebuah stringPunya property,tanpa label()Instance yang bisamemanggil label()
JSON.parse menghasilkan object biasa yang punya property tapi tidak punya method. Baru setelah melewati new, object itu menjadi instance yang bisa memanggil label().

Baris terakhir fromJSON adalah new Parcel(...), jadi body constructor tetap berjalan seperti biasa. Kalau kamu menaruh pengecekan dengan throw di constructor, paket yang dimuat kembali dari JSON juga melewati pengecekan yang sama dengan paket yang diinput di layar.

fromJSON Tidak Bisa Dipanggil dari Instance

Kalau dipanggil dari instance, seperti parcel.fromJSON(text), kode melempar TypeError: parcel.fromJSON is not a function. Berbeda dengan label(), static method hanya bisa dipanggil lewat nama class. Cara kerjanya dibahas di artikel tentang prototype.

Pulihkan item keranjang yang tersimpan dari string JSON. CartItem dan savedTexts sudah dideklarasikan.

① Tambahkan method fromJSON yang membuat lalu mengembalikan instance CartItem dari string JSON.

② Pakai ① untuk mengubah dua data di savedTexts menjadi instance CartItem.

③ Tampilkan "Nama x jumlah = subtotal yen" untuk setiap item.

④ Tampilkan jumlah semua subtotal dalam format "Total: X yen".

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Batas yang Sama untuk Semua Paket — static Constant

Batas berat 30 kg dipakai di dua tempat: di keterangan formulir input, yang tampil sebelum ada paket apa pun, dan di perhitungan sisa kapasitas setiap paket. Kalau batas itu ditaruh di field instance, kamu harus membuat paket tanpa penerima dan tanpa berat hanya untuk menampilkan keterangan di formulir.

Static constant (static field berisi value yang tidak pernah berubah selama program berjalan) diberi nama dengan huruf kapital semua, dan setiap kata dipisah dengan underscore, seperti static MAX_WEIGHT_KG = 30;. Baik dari luar class maupun dari dalam method, kamu membacanya lewat nama class: Parcel.MAX_WEIGHT_KG.

class Parcel {
  // Batas yang berlaku untuk semua paket disimpan sekali di class dengan static
  static MAX_WEIGHT_KG = 30;

  constructor(weightKg) {
    this.weightKg = weightKg;
  }

  // Berapa kg lagi yang masih muat sampai batas
  remainingKg() {
    return Parcel.MAX_WEIGHT_KG - this.weightKg;
    // Kalau ditulis this.MAX_WEIGHT_KG - this.weightKg, hasilnya NaN
  }
}

// Bisa dibaca bahkan sebelum ada instance
console.log(`Maksimal ${Parcel.MAX_WEIGHT_KG} kg per paket`);   // Maksimal 30 kg per paket
const parcel = new Parcel(12);
console.log(parcel.remainingKg());                              // 18
Cara Membaca Batas Menentukan Hasilnya
static MAX_WEIGHT_KG= 30Keterangan form:Parcel.MAX_WEIGHT_KGDi remainingKg:Parcel.MAX_WEIGHT_KGDi remainingKg:this.MAX_WEIGHT_KGMembaca 30tanpa instanceMenghitung30 - 12Bukan di instance:undefinedTampil "Maksimal30 kg per paket"Mengembalikan 18undefined - 12menghasilkan NaN
Kolom kiri dan tengah membaca angka 30 yang sama, dengan atau tanpa instance. Hanya kolom kanan, yang membaca dari this, yang berakhir dengan NaN.

Kolom kanan berakhir dengan NaN karena this di dalam method merujuk ke instance, sedangkan static constant tidak ada di instance. undefined - 12 tidak melempar error, jadi kamu baru sadar saat sisa berat yang ditampilkan terlihat aneh.

Nama Berhuruf Kapital Tetap Bisa Di-assign Ulang

Nama berhuruf kapital hanyalah konvensi yang berarti "jangan diubah"; kalau kamu meng-assign Parcel.MAX_WEIGHT_KG = 50;, value-nya tetap berubah. Kalau kamu hanya mendefinisikan getter, seperti static get MAX_WEIGHT_KG() { return 30; }, assignment ke nama itu melempar TypeError (getter dibahas di artikel berikutnya).

Periksa username berdasarkan aturan panjang karakter. registeredNames sudah dideklarasikan.

① Beri Account panjang nama minimum 3 dan maksimum 12 yang berlaku untuk semua akun.

② Tambahkan isValidName, yang mengembalikan apakah panjang nama ada di dalam rentang tersebut.

③ Ubah setiap nama menjadi Account, lalu tampilkan "nama: valid" atau "nama: tidak valid".

④ Anggap ada bagian kode lain yang tidak sengaja mengubah panjang maksimum menjadi 20. Tambahkan assignment itu, lalu tampilkan lagi hasilnya dalam format yang sama seperti ③.

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Menentukan Tempat Menyimpan Value — static atau Instance

Setelah mengenal static, mungkin terasa praktis kalau value seperti penerima juga ditaruh di class supaya bisa dibaca dari satu tempat, Parcel.recipient. Dalam tes singkat yang hanya membuat satu paket, penerima yang tampil sama saja, baik disimpan di static maupun di this, jadi kamu tidak akan melihat bedanya.

Tentukan tempat menyimpan sebuah value berdasarkan apakah value itu berbeda untuk setiap data. Value yang disimpan di this ada secara terpisah di setiap instance yang dibuat dengan new, sedangkan value static hanya ada satu di class, berapa pun paket yang kamu buat.

// Penerima disimpan di static
class SharedParcel {
  static recipient = "";
  constructor(recipient) { SharedParcel.recipient = recipient; }
  label() { return `Kepada: ${SharedParcel.recipient}`; }
}

// Penerima disimpan di instance
class Parcel {
  constructor(recipient) { this.recipient = recipient; }
  label() { return `Kepada: ${this.recipient}`; }
}

const sharedFirst = new SharedParcel("Budi");
new SharedParcel("Siti");
console.log(sharedFirst.label());   // Kepada: Siti

const first = new Parcel("Budi");
new Parcel("Siti");
console.log(first.label());         // Kepada: Budi
Apakah new Kedua Mengubah Penerima Paket Pertama?
Penerima masuk kestatic recipientnew keduamengisi SitiSatu-satunyapenerima tertimpasharedFirst.label()→ "Kepada: Siti"Penerima masuk kethis.recipientnew kedua adalahinstance terpisahPenerima pertamatetap Budifirst.label()→ "Kepada: Budi"
Di baris atas, penerima paket kedua menimpa satu-satunya value di class. Value yang berbeda untuk setiap data disimpan di this, supaya setiap instance punya value sendiri.

sharedFirst tidak punya penerima sendiri, dan label() membaca SharedParcel.recipient sesuai value-nya saat dipanggil, jadi yang tampil adalah "Siti", value terakhir yang di-assign. Tabel di bawah merangkum member paket di artikel ini: cara menulis dan cara memakai masing-masing.

Yang disimpanCara menulis dan memakaiContoh di sini
Value per dataDi this, baca dari instancenumber / recipient / weightKg
Method untuk value per dataTanpa static, panggil dari instancelabel() / remainingKg()
Satu value untuk semuaDengan static, baca lewat nama classcount / MAX_WEIGHT_KG
Logika tanpa instanceDengan static, panggil lewat nama classfromJSON(text)
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Parcel punya static count = 0;. Apa yang kamu dapat kalau membaca first.count dari instance first?

Soal 2Apa yang terjadi kalau kamu memanggil static method dari instance parcel, seperti parcel.fromJSON(text)?

Soal 3Sebuah class menyimpan penerima di static field. Kalau kamu membuat paket untuk "Budi" lalu paket untuk "Siti", penerima apa yang ditampilkan label() milik paket pertama?