Menu

Symbol JavaScript: Key Unik, Symbol.iterator, dan Lainnya

Apa itu symbol di JavaScript, kenapa symbol ada, dan bagaimana well-known symbol seperti Symbol.iterator membuat object buatanmu terhubung ke fitur bahasa.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Symbol adalah nilai yang dijamin unik

Symbol adalah salah satu tipe primitif JavaScript, bersama string, number, boolean, null, undefined, dan bigint. Sifat utamanya sederhana: setiap symbol yang kamu buat berbeda dari symbol lain mana pun, selamanya.

Dua symbol, sama-sama dibuat tanpa argumen, tapi tetap tidak sama. Itu bukan kebetulan, justru itulah intinya. Kamu tidak bisa memalsukan symbol, membuatnya ulang tanpa sengaja, atau bertabrakan dengan symbol milik orang lain.

Kamu bisa menambahkan deskripsi untuk membantu debugging. Deskripsi tidak memengaruhi identitasnya:

Deskripsinya sama, symbol-nya berbeda. Deskripsi itu murni label untuk manusia yang membaca log.

Kenapa symbol ada: key yang bebas tabrakan

Alasan utama symbol ada adalah supaya kamu bisa menambahkan property ke sebuah object tanpa khawatir key-mu bentrok dengan milik orang lain. Key berupa string bersaing dalam satu namespace datar: kalau dua library sama-sama memutuskan menyimpan metadata di obj.meta, mereka saling menimpa. Key berupa symbol tidak bersaing, karena tidak ada orang lain yang memegang symbol-mu.

Kurung siku di [ID]: 42 adalah sintaks computed property: artinya "pakai nilai ID sebagai key." Hanya kode yang memegang symbol ID yang sama yang bisa membaca atau menimpa property itu. Module lain yang memakai string "id" atau Symbol("id") miliknya sendiri sedang membicarakan slot yang sama sekali berbeda.

Key berupa symbol (umumnya) tersembunyi

Property dengan key symbol tidak muncul di for...in, Object.keys, atau JSON.stringify. Property itu bukan rahasia, karena kode yang memang berniat mencarinya tetap bisa menemukannya, tapi ia tidak mengganggu saat perulangan biasa.

Object.keys dan JSON.stringify melewati key symbol sepenuhnya. Kalau kamu memang perlu menemukan property symbol, Object.getOwnPropertySymbols dan Reflect.ownKeys menampilkannya. Inilah perilaku yang tepat untuk metadata: terlihat saat kamu mencarinya, tidak terlihat oleh kode yang hanya menelusuri key berupa string.

Berbagi symbol dengan Symbol.for

Symbol() memberimu symbol lokal yang sekali pakai. Kadang kamu ingin kebalikannya: symbol yang sama di mana pun dalam program, lintas module, sehingga bagian-bagian kode yang berbeda bisa menyepakati satu key. Untuk itulah Symbol.for.

Symbol.for(key) mengecek registry global: kalau symbol untuk key itu sudah ada, kamu mendapatkannya kembali; kalau belum, ia membuat yang baru lalu menyimpannya. Symbol.keyFor bekerja ke arah sebaliknya: ia mengembalikan key yang dipakai untuk membuat symbol yang terdaftar (atau undefined untuk yang tidak terdaftar).

Sebagian besar waktu, Symbol() biasa sudah cukup. Pakai Symbol.for saat sebuah symbol benar-benar perlu dipakai bersama melintasi batas module.

Well-known symbol: kait ke dalam bahasa

Di sinilah symbol benar-benar berguna. JavaScript menyediakan sekumpulan symbol bawaan, yaitu well-known symbol, yang dicek oleh bahasanya sendiri pada object-mu. Buat method di salah satu key ini, dan object-mu langsung terhubung ke sebuah fitur bawaan.

Yang paling berguna adalah Symbol.iterator. Object apa pun yang punya method di key ini bersifat iterable: ia bisa dipakai dengan for...of, spread, destructuring, dan Array.from.

range bukan array. Ia object biasa dengan satu method ber-key khusus. Tapi karena method itu mengembalikan iterator, for...of dan spread sama-sama bisa dipakai padanya, sama seperti pada array, string, dan Map. Itulah kontraknya: implementasikan Symbol.iterator, dan bahasanya akan memperlakukanmu sebagai iterable.

Well-known symbol lain yang perlu kamu tahu

Masih ada beberapa lagi, masing-masing menjadi kait ke bagian bahasa yang berbeda:

  • Symbol.iterator: membuat object menjadi iterable.
  • Symbol.asyncIterator: sama, tapi untuk for await...of.
  • Symbol.toPrimitive: mengatur cara object diubah menjadi primitif (number, string, atau default) dalam konteks konversi tipe.
  • Symbol.hasInstance: menyesuaikan hasil instanceof untuk class-mu.
  • Symbol.toStringTag: mengatur tag yang ditampilkan di Object.prototype.toString.call(obj).

Kamu tidak perlu menghafalnya. Cukup tahu bahwa semuanya ada: saat kamu ingin object-mu berperilaku seperti tipe bawaan, biasanya ada well-known symbol untuk itu.

Symbol bukan string

Jebakan yang umum: symbol tidak otomatis diubah menjadi string. Menyambungnya dengan string akan melempar error, begitu juga mengirimnya ke API yang mengharapkan string:

Template literal melempar TypeError yang sama. Pakai String(symbol) atau symbol.toString() saat kamu memang ingin teks. Sisi kasar ini disengaja: bahasanya melindungimu agar tidak tanpa sengaja memperlakukan nilai identitas yang unik sebagai potongan data string biasa.

Kapan memakai symbol (dan kapan tidak)

Pakai symbol saat:

  • Kamu menempelkan metadata ke object yang bukan milikmu, dan butuh key yang tidak akan bentrok.
  • Kamu merancang sebuah protokol: "object yang ingin bekerja dengan library-ku harus mengimplementasikan method di symbol ini."
  • Kamu ingin property yang tidak bocor ke JSON.stringify atau for...in.
  • Kamu mengimplementasikan Symbol.iterator atau well-known symbol lainnya.

Lewati symbol saat:

  • Kamu hanya butuh key object dan tidak ada risiko bentrok. String lebih sederhana dan tampil apa adanya di log.
  • Kamu menginginkan field "private". Property dengan key symbol tidak benar-benar private: Object.getOwnPropertySymbols bisa menemukannya. Untuk privasi sungguhan, pakai field class #private.
  • Kamu menyimpan data yang harus tetap ada setelah JSON.stringify. Data itu tidak akan ikut.

Sebagian besar kode JavaScript baik-baik saja tanpa pernah menulis Symbol(...) secara langsung. Tapi begitu kamu ingin object-mu bisa dipakai dengan for...of atau berperilaku wajar dalam konteks konversi tipe, symbol adalah pintu masuk ke mesin itu.

Berikutnya: deklarasi fungsi

Symbol, iterator, dan generator semuanya sangat bergantung pada fungsi: method yang disimpan di Symbol.iterator, factory yang mengembalikan iterator, generator yang bentuk function*-nya menyembunyikan sebagian besar boilerplate. Fungsi adalah bab berikutnya, dimulai dengan berbagai cara mendeklarasikannya dan apa yang berubah di antara setiap bentuk.

Pertanyaan yang sering diajukan

Apa itu symbol di JavaScript?

Symbol adalah tipe primitif yang nilainya dijamin unik. Kamu membuatnya dengan Symbol() atau Symbol('description'), dan tidak ada dua pemanggilan yang pernah menghasilkan symbol yang sama. Symbol terutama dipakai sebagai key object yang tidak akan bertabrakan dengan key lain, dan sebagai kait ke fitur bahasa lewat well-known symbol seperti Symbol.iterator.

Kapan sebaiknya memakai symbol alih-alih key berupa string?

Pakai symbol saat kamu ingin menempelkan property ke sebuah object tanpa risiko bentrok nama dengan kode lain: library yang menambah metadata, framework yang menandai object, atau key yang sengaja tidak dijadikan bagian dari API publik. Untuk key sehari-hari yang mengutamakan keterbacaan dan tidak berisiko bentrok, string tetap pilihan yang tepat.

Untuk apa Symbol.iterator dipakai?

Symbol.iterator adalah well-known symbol yang memberi tahu for...of, spread, dan destructuring cara menelusuri sebuah object. Kalau kamu mendefinisikan method di key Symbol.iterator yang mengembalikan iterator, object-mu menjadi iterable. Begitulah array, string, Map, dan Set bekerja di balik layar.

Apa bedanya Symbol() dan Symbol.for()?

Symbol('x') membuat symbol baru setiap kali dipanggil: dua pemanggilan dengan deskripsi yang sama tetap berbeda. Symbol.for('x') mencari di registry global dan mengembalikan symbol yang sama untuk key yang sama di seluruh program. Pakai Symbol.for saat symbol perlu dipakai bersama antar-module atau realm; pakai Symbol() untuk keunikan lokal.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai