Kodeloka
  1. Kodeloka
  2. Kelas JavaScript
  3. Materi

2 · Objek & Data · Modul 6 dari 22

Koleksi Berbasis Kunci: Map, Set (Metode Himpunan Baru), WeakMap, dan Symbol

Memilih struktur data yang tepat antara Map vs Object dan Set vs Array, memanfaatkan metode operasi himpunan Set terbaru (union, intersection, difference), mencegah kebocoran memori dengan WeakMap, serta mengenal Symbol.

Mengapa Object dan Array Saja Tidak Selalu Cukup?

Meskipun Object ({}) dan Array ([]) sangat fleksibel, keduanya memiliki keterbatasan struktural ketika menangani ribuan data dinamis:

  1. Kunci properti pada Object biasa selalu dipaksa menjadi string (atau Symbol). Anda tidak bisa menjadikan elemen DOM atau objek lain sebagai kunci di dalam {}.
  2. Memeriksa apakah sebuah nilai ada di dalam Array berukuran 100.000 elemen menggunakan array.includes(x) membutuhkan pencarian satu per satu dari awal hingga akhir (O(n)), sedangkan pencarian pada Set berlangsung nyaris instan (O(1))!

1. Map: Kamus Pasangan Kunci-Nilai Berkinerja Tinggi

Map menyimpan pasangan kunci-nilai (key-value pairs) dengan keunggulan utama dibandingkan Object biasa:

KarakteristikMap (new Map())Object Biasa ({})
Tipe Kunci yang DiizinkanApa saja! (String, angka, boolean, fungsi, objek lain, bahkan elemen DOM).Hanya string dan Symbol (angka 1 otomatis diubah menjadi string "1").
Menghitung Jumlah ItemInstan melalui properti map.size.Harus membuat array dulu lewat Object.keys(obj).length.
Keamanan Kunci Masukan PenggunaAman dari benturan dengan properti bawaan prototipe (seperti "toString" atau "constructor").Rawan bentrok dengan Object.prototype kecuali dibuat dengan Object.create(null).
Urutan IterasiDijamin selalu sesuai **urutan penyisipan (insertion order)**.Kunci string angka diurutkan lebih dulu sebelum kunci huruf.
const sesiAktif = new Map();

// Menambahkan data dengan .set(kunci, nilai)
sesiAktif.set("usr_101", { nama: "Ayu", peran: "admin" });
sesiAktif.set("usr_102", { nama: "Raka", peran: "editor" });

console.log(sesiAktif.size);           // 2
console.log(sesiAktif.has("usr_101")); // true
console.log(sesiAktif.get("usr_101")); // { nama: "Ayu", peran: "admin" }

// Mengiterasi Map secara langsung dengan for...of
for (const [idPengguna, info] of sesiAktif) {
  console.log(`${idPengguna}: ${info.nama} (${info.peran})`);
}

// Menghapus satu item dengan .delete(kunci), atau mengosongkan semua dengan .clear()
sesiAktif.delete("usr_102");
⚠️ Kesalahan Umum pada Map

Jangan mengakses atau mengisi Map menggunakan kurung siku seperti objek (peta["kunci"] = 123)! Menulis peta["kunci"] tidak menyimpan data ke dalam struktur internal Map (sehingga peta.size tetap 0), melainkan hanya menempelkan properti objek biasa di luar Map. Selalu gunakan metode .set(kunci, nilai), .get(kunci), .has(kunci), dan .delete(kunci).

2. Set dan Metode Operasi Himpunan Matematika Terbaru

Set adalah koleksi nilai berurutan yang menjamin setiap nilainya unik (tidak mungkin ada duplikat).

Kegunaan paling populer dari Set:

  1. Menghapus duplikat dari sebuah Array dalam satu baris: const daftarUnik = [...new Set(daftarDenganDuplikat)];
  2. Memeriksa keberadaan item dengan sangat cepat (set.has(nilai) — O(1)).

Operasi Himpunan Set Modern (Baseline Newly Available sejak 2024)

Kini Anda tidak perlu lagi menulis .filter() manual untuk mencari irisan atau gabungan dua himpunan. Set.prototype telah dilengkapi 7 metode himpunan matematika bawaan:

const keahlianBackend  = new Set(["Go", "PHP", "PostgreSQL", "Docker"]);
const keahlianDevOps   = new Set(["Linux", "Docker", "Kubernetes", "PostgreSQL"]);

// 1. intersection(): Irisan — elemen yang ada di KEDUA himpunan
const irisan = keahlianBackend.intersection(keahlianDevOps);
console.log([...irisan]); // ["PostgreSQL", "Docker"]

// 2. union(): Gabungan seluruh elemen unik dari kedua himpunan
const gabungan = keahlianBackend.union(keahlianDevOps);
console.log([...gabungan]); // ["Go", "PHP", "PostgreSQL", "Docker", "Linux", "Kubernetes"]

// 3. difference(): Selisih — ada di Backend, tetapi TIDAK ada di DevOps
const khususBackend = keahlianBackend.difference(keahlianDevOps);
console.log([...khususBackend]); // ["Go", "PHP"]

// 4. Pemeriksaan hubungan himpunan (menghasilkan boolean):
console.log( new Set(["Go", "PHP"]).isSubsetOf(keahlianBackend) ); // true

3. Mencegah Kebocoran Memori dengan WeakMap dan WeakSet

Apa yang terjadi jika Anda menggunakan objek (misalnya simpul elemen DOM <button> yang dinamis) sebagai kunci di dalam Map biasa, lalu elemen <button> tersebut dihapus dari halaman HTML?

  • Karena Map biasa memegang **referensi kuat (strong reference)** ke elemen <button> tersebut, Garbage Collector tidak berani membebaskan memori elemen <button> itu selama entri di Map belum dihapus secara manual! Inilah penyebab umum kebocoran memori (memory leak) pada aplikasi Single-Page Application (SPA).

Solusinya adalah WeakMap (dan WeakSet):

  • Kunci pada WeakMap wajib berupa Objek (atau simbol non-registrasi).
  • Referensi ke objek kuncinya bersifat **lemah (weak reference)**: begitu objek kunci tersebut tidak lagi dirujuk oleh variabel lain di program (misalnya elemen DOM-nya sudah dihapus dari layar), Garbage Collector otomatis menghapus entri tersebut dari WeakMap dan membebaskan memorinya!
  • Karena isinya dapat dibersihkan sewaktu-waktu oleh Garbage Collector, WeakMap tidak dapat diiterasi (for...of) dan tidak memiliki properti .size.
// Menyimpan metadata internal yang terikat pada objek tanpa mencegah Garbage Collection
const metadataKomponen = new WeakMap();

let tombolSementara = { id: "btn-1", teks: "Simpan" };
metadataKomponen.set(tombolSementara, { jumlahKlik: 5 });

console.log(metadataKomponen.get(tombolSementara)); // { jumlahKlik: 5 }

// Ketika referensi ke objek dihapus, entri di WeakMap ikut siap dibersihkan oleh GC!
tombolSementara = null;

4. Symbol: Kunci Properti Unik yang Bebas Benturan

Symbol adalah tipe primitif yang setiap pemanggilannya dijamin menghasilkan nilai unik yang tidak pernah sama (Symbol("id") !== Symbol("id")). Ia digunakan untuk:

  1. Menambahkan properti tersembunyi/internal pada objek tanpa khawatir tertimpa oleh kode lain atau ikut tercetak di JSON.stringify().
  2. Mendefinisikan perilaku protokol bawaan bahasa melalui Well-Known Symbols seperti Symbol.iterator (yang membuat objek kustom Anda bisa diiterasi dengan for...of!).

Latihan Praktik: Mengelola Hak Akses Pengguna dengan Map dan Set

Buatlah berkas hak-akses.js dan jalankan dengan Node.js:

  1. Buat Map bernama peranPengguna yang memetakan nama peran ("admin", "penulis", "pembaca") ke sebuah objek Set berisi daftar izin (permissions, misalnya "baca", "tulis", "terbitkan", "hapus").
  2. Buat fungsi punyaIzin(peran, izinYangDicari) yang memeriksa secara cepat dalam waktu O(1) apakah peran tersebut memiliki izin yang diminta.
  3. Gunakan metode .difference() pada Set untuk mencetak izin apa saja yang dimiliki "admin" tetapi tidak dimiliki oleh "penulis".