Map, Set, symbol

Struktur data Map dan Set serta tipe symbol melampaui object polos.

Daftar isi

Object polos menampung data berupa pasangan kunci dan nilai, tetapi object bukan alat yang tepat untuk semua koleksi. Topik ini memperkenalkan Map yang menerima kunci bertipe apa pun, Set yang menyimpan nilai unik, dan symbol sebagai tipe kunci yang selalu unik. Ketiganya menggantikan trik yang sebelumnya dipakai untuk mengakali keterbatasan object, seperti mengubah object menjadi string agar bisa dijadikan kunci.

Map ketika kunci bukan hanya string#

Map menyimpan pasangan kunci dan nilai dengan kunci yang boleh bertipe apa pun, sedangkan object selalu mengubah kuncinya menjadi string atau symbol. Isi Map diatur lewat metode, yaitu set untuk menambahkan, get untuk membaca, has untuk menguji keberadaan, dan delete untuk menghapus, sementara jumlah pasangannya terbaca langsung dari properti size.

js Contoh: Map dengan kunci string dan object
const stok = new Map();
stok.set("pensil", 40);
stok.set("buku", 25);
stok.set("pensil", 38); // kunci sama, nilainya diganti
console.log(stok.size);
console.log(stok.get("pensil"));

const rakA = { kode: "A" };
const rakB = { kode: "B" };
stok.set(rakA, 12);
stok.set(rakB, 7);
console.log(stok.get(rakA));
console.log(stok.size);

const objekBiasa = {};
objekBiasa[rakA] = 12;
objekBiasa[rakB] = 7;
console.log(Object.keys(objekBiasa).length);
console.log(Object.keys(objekBiasa)[0]);
text Keluaran
2
38
12
4
1
[object Object]

Setengah pertama keluaran menunjukkan perilaku yang wajar. Kunci pensil yang ditambahkan dua kali lewat set tidak menduplikasi pasangan, melainkan mengganti nilainya, dan size ikut bertambah setelah dua object rak menjadi kunci. Setengah kedua memperlihatkan perbedaannya dengan object. Dua object berbeda yang dipakai sebagai kunci object biasa menyatu menjadi satu karena keduanya diubah menjadi string "[object Object]", sedangkan Map menyimpannya sebagai dua kunci terpisah berdasarkan identitas referensinya. Perulangan for...of atas Map menghasilkan pasangan kunci dan nilai dalam urutan penambahannya, dan urutan ini dijamin oleh spesifikasi, bukan sekadar kebetulan implementasi.

Kapan Map lebih tepat daripada object#

Pilihan antara Map dan object mengikuti bentuk datanya, bukan selera. Perbandingan berikut merangkum aspek yang membedakan keduanya.

AspekMapObject
Tipe kunciapa pun, termasuk objectstring dan symbol
Jumlah pasanganproperti sizehitung Object.keys manual
Urutanurutan penambahanumumnya urutan penambahan, dengan pengecualian kunci yang menyerupai indeks
Konversi JSONbukan data JSON, stringify menghasilkan {}asli sebagai data JSON
Cocok untukkoleksi yang sering bertambah dan berkurangdata terstruktur yang bentuknya tetap

Dua kriteria praktis paling sering menentukan pilihan. Pertama, kunci yang lahir saat program berjalan, misalnya object pembeli sebagai kunci keranjangnya atau hitungan frekuensi per kata, cocok untuk Map karena kuncinya dinamis. Kedua, data yang dikirim dan diterima sebagai JSON tetap memakai object, karena Map tidak punya bentuk JSON dan harus dikonversi dulu menjadi array atau object sebelum dikirim. Pemisahan ini juga menjelaskan mengapa keduanya tetap dipakai berdampingan pada program yang sama, yaitu object untuk menyusun data dan Map untuk mengindeksnya saat berjalan.

Set untuk keanggotaan dan dedup#

Set menyimpan nilai-nilai yang unik, dan penambahan nilai yang sama untuk kedua kalinya diabaikan. Sifat ini menjadikan Set alat yang ringkas untuk dua pekerjaan, yaitu menguji keanggotaan lewat has dan menghilangkan duplikat array lewat konversi ke Set lalu spread kembali.

js Contoh: Set untuk menghilangkan duplikat dan menguji keanggotaan
const angka = [7, 7, 12, 7, 12, 30];
const unik = new Set(angka);
console.log(unik);
console.log([...unik]);
console.log(unik.has(12));
unik.add(30);
console.log(unik.size);
text Keluaran
Set(3) { 7, 12, 30 }
[ 7, 12, 30 ]
true
3

Baris pertama memperlihatkan enam angka yang hanya menyisakan tiga anggota, dan baris kedua mengembalikannya menjadi array tanpa duplikat lewat spread. Pada baris keempat, add(30) tidak mengubah apa pun karena 30 sudah menjadi anggota, sehingga size tetap 3. Pengujian has bekerja cepat untuk koleksi besar karena Set mengindeks anggotanya, berbeda dari includes pada array yang memeriksa satu per satu dari awal.

symbol sebagai kunci yang unik#

symbol adalah tipe primitif yang nilainya selalu unik, sehingga dua symbol dengan deskripsi yang sama tetap berbeda. Deskripsi pada Symbol("id") hanya penanda untuk manusia yang membaca kode, sedangkan identitasnya ditetapkan saat pembuatan dan tidak bisa ditiru oleh symbol lain. Untuk kebutuhan berbagi, Symbol.for("nama") mencari symbol pada registry global dan membuatnya bila belum ada. Dua berkas yang memanggil Symbol.for dengan nama yang sama menerima symbol yang sama, dan Symbol.keyFor membaca nama itu kembali.

js Contoh: identitas symbol, registry, dan kunci tersembunyi
const id = Symbol("id");
const idLain = Symbol("id");
console.log(id === idLain);
console.log(typeof id);

const pencatat = Symbol.for("pencatat");
const pencatatJuga = Symbol.for("pencatat");
console.log(pencatat === pencatatJuga);
console.log(Symbol.keyFor(pencatat));

const data = { nama: "Citra", [id]: 42 };
console.log(JSON.stringify(data));
console.log(Object.keys(data));
console.log(data[id]);
text Keluaran
false
symbol
true
pencatat
{"nama":"Citra"}
[ 'nama' ]
42

Tiga baris terakhir adalah inti pemakaiannya. Symbol id yang menjadi kunci object tidak terlihat oleh JSON.stringify maupun Object.keys, sehingga data yang dikirim keluar tidak membawanya. Kode di dalam berkas yang sama tetap bisa membacanya lewat akses kurung siku. Kunci seperti ini cocok untuk properti internal yang tidak boleh bentrok dengan properti dari sumber luar, misalnya metadata yang ditempelkan pada data milik pustaka lain. Sifatnya perlu diingat, yakni symbol bukan penyimpanan privat sejati karena Object.getOwnPropertySymbols tetap mendaftar kunci-kunci tersebut bagi siapa pun yang mencarinya.

Ringkasan#

  • Map menerima kunci bertipe apa pun, menghitung isinya lewat size, dan menjaga urutan penambahan, sedangkan object memaksakan kunci string dan symbol.
  • Map untuk kunci dinamis dan koleksi yang sering berubah, object untuk data terstruktur yang dikirim sebagai JSON.
  • Set menyimpan anggota unik, menguji keanggotaan lewat has, dan menghilangkan duplikat array lewat new Set(array) lalu spread kembali.
  • symbol selalu unik, Symbol.for berbagi lewat registri global, dan kunci symbol tersembunyi dari Object.keys maupun JSON.stringify tanpa menjadi penyimpanan privat sejati.

Referensi#