Masalahnya dengan garis bawah
Selama bertahun-tahun, JavaScript tidak punya private field. Konvensinya adalah memberi awalan garis bawah pada sebuah property dan berharap semua orang menghormatinya:
_count terlihat private, padahal tidak. Pemanggil mana pun bisa membacanya, menulisnya, atau menghapusnya. Garis bawah itu ibarat papan sopan di pintu; pintunya sendiri terbuka lebar.
JavaScript modern memperbaiki ini dengan private field sungguhan, yang ditandai dengan #.
# membuatnya private
Beri awalan # pada nama field di deklarasi dan di setiap tempat ia diakses:
Dari dalam class, this.#count berfungsi seperti biasa. Dari luar, ia tidak ada:
# benar-benar bagian dari nama field. Ia bukan kata kunci modifier seperti private di bahasa lain, melainkan tanda yang dipakai parser untuk mencari slot terpisah yang terlindungi di object itu. Karena itulah error-nya muncul saat parsing, bahkan sebelum kode dijalankan.
Private method dan getter
Bukan hanya field yang bisa ditandai private. Method, getter, dan setter semuanya menerima awalan #:
#assertPositive adalah helper internal. Ia bukan bagian dari API publik, jadi membuatnya benar-benar private berarti tidak ada yang tanpa sengaja memanggilnya dari luar, dan tidak ada yang bisa bergantung padanya, sehingga kamu tetap bebas mengganti namanya atau menghapusnya nanti.
Private static member
Static member juga bisa private. Beri awalan # dengan cara yang sama:
Static private tinggal di class itu sendiri, bukan di instance. Berguna untuk counter, cache, atau konfigurasi yang tidak boleh bocor keluar dari class.
Subclass tidak bisa melihatnya
Ini sering menjebak orang yang datang dari Java atau C#. Private field di JavaScript bersifat class-private, bukan instance-private. Subclass tidak bisa menjangkau private field milik induknya:
Tidak ada protected di JavaScript. Kalau subclass butuh datanya, class induk harus menyediakan method, getter, atau (lebih jarang) field yang tidak private. Desainnya disengaja: private benar-benar berarti private, dan pewarisan tidak membuat lubang di dalamnya.
Mengecek private field dengan in
Kadang kamu ingin memastikan sebuah object benar-benar milik class-mu, yang disebut brand check. Operator in bisa dipakai dengan nama private field di dalam class:
Karena hanya Wallet yang bisa membuat object dengan #balance, #balance in obj adalah tes yang andal bahwa obj adalah instance Wallet yang asli. Dalam beberapa kasus tepi, ini lebih cepat dan lebih aman daripada instanceof, karena private field tidak bisa dipalsukan dari luar.
Jebakan umum: object biasa tidak memilikinya
Private field tinggal di instance yang dibuat oleh constructor class. Kalau kamu mencoba memakainya pada object yang tidak dibuat dengan new, ia melempar error:
Memanggil method dengan this yang bukan Point akan melempar error saat runtime. Inilah mekanisme di balik brand check di atas: private field terikat ke class tertentu yang mendeklarasikannya, bukan ke object apa pun yang kebetulan terlihat cocok.
Kapan memakai #
Gunakan private field sebagai default setiap kali sebuah state atau helper bukan bagian dari API publik class. Alasannya:
- Bebas refactor. Pemanggil tidak bisa bergantung pada bagian internal yang memang tidak bisa mereka lihat.
- Enkapsulasi sungguhan. Tidak ada pembacaan, penulisan, atau penghapusan tak sengaja dari kode luar.
- Autocomplete lebih bersih. Editor tidak menyarankan member private ke pemanggil dari luar.
Pakai property publik saat sesuatu memang bagian dari antarmuka. Pakai getter (get name()) saat kamu ingin akses read-only ke private field. Tinggalkan konvensi garis bawah: itu dulu hanya akal-akalan untuk celah yang kini sudah diisi oleh bahasanya.
#celsius adalah penyimpanan tersembunyi; celsius dan fahrenheit adalah tampilan read-only. Pemanggil tidak bisa merusak state internalnya, dan class tetap bebas mengubah cara ia menyimpan nilai itu nanti.
Berikutnya: prototype
Class sebagian besar adalah syntactic sugar di atas sistem prototype JavaScript, model yang lebih tua dan lebih mendasar yang sebenarnya menjadi fondasi bahasa ini. Memahami prototype menjelaskan kenapa this berperilaku seperti itu, bagaimana pewarisan sebenarnya bekerja, dan apa yang di-extends sebuah class di balik layar. Itulah halaman berikutnya.
Pertanyaan yang sering diajukan
Bagaimana cara mendeklarasikan private field di JavaScript?
Beri awalan # pada nama field, baik saat deklarasi maupun setiap kali kamu mengaksesnya. class Counter { #count = 0; increment() { this.#count++; } } membuat field yang benar-benar private. # adalah bagian dari nama, bukan operator.
Apa bedanya #field dan _field di JavaScript?
_field hanyalah konvensi penamaan: property-nya tetap publik dan siapa pun bisa membaca atau menulisnya. #field ditegakkan oleh bahasanya: kode di luar class benar-benar tidak bisa mengaksesnya, dan mencobanya akan melempar SyntaxError saat parsing. Pakai # kalau kamu ingin privasi sungguhan.
Apakah subclass bisa mengakses private field milik class induknya?
Tidak. Private field hanya berlaku di class yang mendeklarasikannya, bahkan subclass pun tidak bisa menyentuhnya. Kalau subclass butuh akses, class induk harus menyediakan method atau getter. Ini lebih ketat daripada protected di bahasa lain, dan memang disengaja.
Bisakah aku mengecek apakah sebuah object punya private field?
Bisa, dengan operator in di dalam class: #field in obj mengembalikan true kalau obj punya private field itu. Ini berguna untuk brand check, yaitu memastikan sebuah object benar-benar instance dari class-mu sebelum memanggil method-nya.