Apakah mungkin membuat properti pribadi di kelas ES6?
Ini sebuah contoh. Bagaimana saya bisa mencegah akses instance.property
?
class Something {
constructor(){
this.property = "test";
}
}
var instance = new Something();
console.log(instance.property); //=> "test"
Jawaban:
Bidang pribadi (dan metode) sedang diterapkan dalam standar ECMA . Anda dapat mulai menggunakannya hari ini dengan babel 7 dan tahap 3 yang telah ditetapkan.
sumber
this
konstruktor sebelum meneleponsuper()
. Namun babel menempatkan mereka di depan super.#privateCrap
sintaks?#beep() {}
:; dan iniasync #bzzzt() {}
:?Jawaban singkat, tidak, tidak ada dukungan asli untuk properti pribadi dengan kelas ES6.
Tetapi Anda bisa meniru perilaku itu dengan tidak melampirkan properti baru ke objek, tetapi menyimpannya di dalam konstruktor kelas, dan menggunakan getter dan setter untuk mencapai properti tersembunyi. Perhatikan bahwa getter dan setter mendapat definisi ulang pada setiap instance baru kelas.
ES6
ES5
sumber
class
sintaksis di tempat pertama.getName
dansetName
properti pribadi?Untuk memperluas jawaban @ loganfsmyth:
Satu-satunya data yang benar-benar pribadi dalam JavaScript masih variabel cakupan. Anda tidak dapat memiliki properti pribadi dalam arti properti yang diakses secara internal dengan cara yang sama seperti properti publik, tetapi Anda dapat menggunakan variabel scoped untuk menyimpan data pribadi.
Variabel cakupan
Pendekatan di sini adalah dengan menggunakan ruang lingkup fungsi konstruktor, yang bersifat pribadi, untuk menyimpan data pribadi. Agar metode memiliki akses ke data pribadi ini, mereka juga harus dibuat di dalam konstruktor, artinya Anda membuat ulang dengan setiap contoh. Ini adalah penalti kinerja dan memori, tetapi beberapa percaya penalti itu dapat diterima. Hukuman dapat dihindari untuk metode yang tidak memerlukan akses ke data pribadi dengan menambahkannya ke prototipe seperti biasa.
Contoh:
WeakMap Bercakupan
WeakMap dapat digunakan untuk menghindari kinerja pendekatan dan memori memori sebelumnya. WeakMaps mengaitkan data dengan Objects (di sini, instance) sedemikian rupa sehingga hanya dapat diakses menggunakan WeakMap itu. Jadi, kami menggunakan metode variabel lingkup untuk membuat WeakMap pribadi, lalu gunakan WeakMap itu untuk mengambil data pribadi yang terkait dengannya
this
. Ini lebih cepat daripada metode variabel cakupan karena semua instance Anda dapat membagikan WeakMap tunggal, jadi Anda tidak perlu membuat ulang metode hanya untuk membuatnya mengakses WeakMaps mereka sendiri.Contoh:
Contoh ini menggunakan Objek untuk menggunakan satu WeakMap untuk beberapa properti pribadi; Anda juga dapat menggunakan beberapa WeakMaps dan menggunakannya
age.set(this, 20)
, atau menulis pembungkus kecil dan menggunakannya dengan cara lain, sepertiprivateProps.set(this, 'age', 0)
.Privasi dari pendekatan ini secara teoritis dapat dilanggar dengan merusak
WeakMap
objek global . Karena itu, semua JavaScript dapat dipatahkan oleh global yang hancur. Kode kami sudah dibangun dengan asumsi bahwa ini tidak terjadi.(Metode ini juga bisa dilakukan
Map
, tetapiWeakMap
lebih baik karenaMap
akan membuat kebocoran memori kecuali Anda sangat berhati-hati, dan untuk tujuan ini keduanya tidak berbeda.)Setengah Jawab: Simbol yang Dicakup
Simbol adalah jenis nilai primitif yang dapat berfungsi sebagai nama properti. Anda dapat menggunakan metode variabel cakupan untuk membuat Simbol pribadi, lalu menyimpan data pribadi di
this[mySymbol]
.Privasi metode ini dapat dilanggar menggunakan
Object.getOwnPropertySymbols
, tetapi agak canggung untuk dilakukan.Contoh:
Half-Answer: Menggarisbawahi
Default yang lama, cukup gunakan properti publik dengan awalan garis bawah. Meskipun bukan merupakan properti pribadi dengan cara apa pun, konvensi ini cukup lazim sehingga ia melakukan pekerjaan yang baik dengan mengomunikasikan bahwa pembaca harus memperlakukan properti itu sebagai milik pribadi, yang sering kali menyelesaikan pekerjaannya. Sebagai gantinya selang ini, kami mendapatkan pendekatan yang lebih mudah dibaca, lebih mudah untuk mengetik, dan lebih cepat.
Contoh:
Kesimpulan
Pada ES2017, masih belum ada cara sempurna untuk melakukan properti pribadi. Berbagai pendekatan memiliki pro dan kontra. Variabel yang dicakup benar-benar pribadi; WeakMaps scoped sangat pribadi dan lebih praktis daripada variabel scoped; Simbol yang dicakup cukup pribadi dan praktis; garis bawah sering kali cukup pribadi dan sangat praktis.
sumber
instanceof
. Saya akui bahwa saya memikirkan pendekatan itu hanya untuk kepentingan kelengkapan dan seharusnya lebih memikirkan seberapa besar kemampuannya.Pembaruan: Sebuah proposal dengan sintaksis yang lebih baik sedang dalam perjalanan. Kontribusi dipersilahkan.
Ya, ada - untuk akses cakupan
Symbol
dalam objek - ES6 memperkenalkan s .Simbol itu unik, Anda tidak bisa mendapatkan akses dari luar kecuali dengan refleksi (seperti privat di Java / C #) tetapi siapa pun yang memiliki akses ke simbol di dalam dapat menggunakannya untuk akses utama:
sumber
Object.getOwnPropertySymbols
? ;)const myPrivateMethod = Math.random(); Something.prototype[''+myPrivateMethod] = function () { ... } new Something()[''+myPrivateMethod]();
. Ini bukan benar-benar privasi, itu tidak jelas, dalam arti JavaScript tradisional. Saya akan menganggap JavaScript "pribadi" berarti menggunakan penutupan untuk merangkum variabel. Variabel-variabel tersebut karenanya tidak dapat diakses melalui refleksi.private
danprotected
kata kunci akan jauh lebih bersih daripadaSymbol
atauName
. Saya lebih suka notasi titik daripada notasi braket. Saya ingin tetap menggunakan titik untuk hal-hal pribadi.this.privateVar
Jawabannya adalah tidak". Tetapi Anda dapat membuat akses pribadi ke properti seperti ini:
export
kata kunci.(Saran bahwa Symbols dapat digunakan untuk memastikan privasi benar dalam versi sebelumnya dari spesifikasi ES6 tetapi tidak lagi terjadi: https://mail.mozilla.org/pipermail/es-discuss/2014-January/035604. html dan https://stackoverflow.com/a/22280202/1282216 . Untuk diskusi lebih lama tentang Simbol dan privasi, lihat: https://curiosity-driven.org/private-properties-in-javascript )
sumber
Satu-satunya cara untuk mendapatkan privasi sejati di JS adalah melalui pelingkupan, jadi tidak ada cara untuk memiliki properti yang merupakan anggota
this
yang hanya dapat diakses di dalam komponen. Cara terbaik untuk menyimpan data yang benar-benar pribadi di ES6 adalah dengan WeakMap.Jelas ini mungkin lambat, dan tentu saja jelek, tetapi memang memberikan privasi.
Perlu diingat bahwa BAHKAN INI tidak sempurna, karena Javascript sangat dinamis. Seseorang masih bisa melakukannya
untuk menangkap nilai saat disimpan, jadi jika Anda ingin ekstra hati-hati, Anda harus menangkap referensi lokal
.set
dan.get
menggunakan secara eksplisit alih-alih mengandalkan prototipe yang dapat ditimpa.sumber
get
menjadi satu per metode (misalnyaconst _ = privates.get(this); console.log(_.privateProp1);
).const myObj = new SomeClass(); console.log(privateProp1.get(myObj)) // "I am Private1"
, artinya properti Anda pribadi atau tidak?Untuk referensi lain di masa depan pada pemirsa, saya mendengar sekarang bahwa rekomendasi adalah menggunakan WeakMaps untuk menyimpan data pribadi.
Berikut ini contoh yang lebih jelas dan berfungsi:
sumber
Tergantung pada siapa Anda bertanya :-)
Tidak ada
private
pengubah properti yang termasuk dalam proposal kelas minimal Maksimal yang tampaknya telah masuk ke draft saat ini .Namun, mungkin ada dukungan untuk nama pribadi , yang memungkinkan properti pribadi - dan mereka mungkin dapat digunakan dalam definisi kelas juga.
sumber
Menggunakan modul ES6 (awalnya diusulkan oleh @ d13) bekerja dengan baik untuk saya. Itu tidak meniru properti pribadi dengan sempurna, tetapi setidaknya Anda bisa yakin bahwa properti yang seharusnya pribadi tidak akan bocor di luar kelas Anda. Ini sebuah contoh:
sesuatu
Maka kode konsumsi dapat terlihat seperti ini:
Pembaruan (Penting):
Seperti @DanyalAytekin diuraikan dalam komentar, properti pribadi ini bersifat statis, sehingga cakupannya global. Mereka akan bekerja dengan baik ketika bekerja dengan Lajang, tetapi harus diperhatikan untuk objek Transient. Memperluas contoh di atas:
sumber
private static
.a.say(); // a
harusb.say(); // b
let _message = null
Cara dicoba , tidak begitu keren, ketika memanggil konstruktor beberapa kali, itu mengacaukan.Melengkapi @ d13 dan komentar oleh @ johnny-oshika dan @DanyalAytekin:
Saya kira dalam contoh yang disediakan oleh @ johnny-oshika kita bisa menggunakan fungsi normal alih-alih fungsi panah dan kemudian
.bind
mereka dengan objek saat ini ditambah_privates
objek sebagai parameter kari:sesuatu
main.js
Manfaat yang dapat saya pikirkan:
_greet
dan_updateMessage
bertindak seperti metode pribadi selama kita tidakexport
referensi)_privates
objek yang diikatBeberapa kekurangan yang dapat saya pikirkan:
Cuplikan berjalan dapat ditemukan di sini: http://www.webpackbin.com/NJgI5J8lZ
sumber
Ya - Anda dapat membuat properti enkapsulasi , tetapi belum dilakukan dengan pengubah akses (publik | pribadi) setidaknya tidak dengan ES6.
Berikut adalah contoh sederhana bagaimana hal itu dapat dilakukan dengan ES6:
1 Buat kelas menggunakan kata kelas
2 Di dalamnya konstruktor menyatakan variabel blok-dicakup menggunakan membiarkan ATAU kata-kata dicadangkan const -> karena mereka blok-lingkup mereka tidak dapat diakses dari luar (dienkapsulasi)
3 Untuk mengizinkan beberapa kontrol akses (setter | getter) ke variabel-variabel tersebut, Anda dapat mendeklarasikan metode instan di dalam konstruktornya menggunakan:
this.methodName=function(){}
sintaksisSekarang mari kita periksa:
sumber
new Something();
karena metode Anda dinyatakan dalam konstruktor untuk memiliki akses ke ini variabel pribadi. Itu dapat menyebabkan banyak konsumsi memori jika Anda membuat banyak instance dari kelas Anda, sehingga masalah kinerja. Metode seharusnya dinyatakan di luar lingkup konstruktor. Komentar saya lebih merupakan penjelasan tentang kekurangan solusi Anda daripada kritik.Pendekatan berbeda untuk "pribadi"
Alih-alih melawan fakta bahwa visibilitas pribadi saat ini tidak tersedia di ES6, saya memutuskan untuk mengambil pendekatan yang lebih praktis yang tidak masalah jika IDE Anda mendukung JSDoc (misalnya, Webstorm). Idenya adalah menggunakan
@private
tag . Sejauh pengembangan berjalan, IDE akan mencegah Anda mengakses anggota pribadi dari luar kelasnya. Berfungsi cukup baik untuk saya dan sudah sangat berguna untuk menyembunyikan metode internal sehingga fitur lengkapi-otomatis menunjukkan kepada saya apa yang sebenarnya ingin diungkapkan oleh kelas. Ini sebuah contoh:sumber
@private
Komentar Anda tidak dapat mencegah ini, itu hanya Fitur untuk pembuatan dokumentasi dan IDE Anda.WeakMap
Object.getOwnPropertySymbols
)Pertama, tentukan fungsi untuk membungkus WeakMap:
Kemudian, buat referensi di luar kelas Anda:
Catatan: kelas tidak didukung oleh IE11, tetapi terlihat lebih bersih dalam contoh.
sumber
Oh, banyak sekali solusi eksotis! Saya biasanya tidak peduli dengan privasi jadi saya menggunakan "privasi semu" seperti yang dikatakan di sini . Tetapi jika peduli (jika ada beberapa persyaratan khusus untuk itu) saya menggunakan sesuatu seperti dalam contoh ini:
Kemungkinan implementasi fungsi lainnya (konstruktor)
Job
:sumber
Secara pribadi saya suka proposal dari operator mengikat
::
dan kemudian akan menggabungkannya dengan solusi @ d13 yang disebutkan tetapi untuk sekarang tetap dengan jawaban @ d13 di mana Anda menggunakanexport
kata kunci untuk kelas Anda dan meletakkan fungsi pribadi dalam modul.ada satu lagi solusi sulit yang belum disebutkan di sini yang berikut adalah pendekatan yang lebih fungsional dan akan memungkinkannya untuk memiliki semua alat peraga / metode pribadi di dalam kelas.
Private.js
Test.js
komentar tentang itu akan sangat dihargai.
sumber
Saya menemukan posting ini ketika mencari praktik terbaik untuk "data pribadi untuk kelas". Disebutkan bahwa beberapa pola akan memiliki masalah kinerja.
Saya mengumpulkan beberapa tes jsperf berdasarkan 4 pola utama dari buku online "Exploring ES6":
http://exploringjs.com/es6/ch_classes.html#sec_private-data-for-classes
Tes dapat ditemukan di sini:
https://jsperf.com/private-data-for-classes
Di Chrome 63.0.3239 / Mac OS X 10.11.6, pola berkinerja terbaik adalah "Data pribadi melalui lingkungan konstruktor" dan "Data pribadi melalui konvensi penamaan". Bagi saya Safari berkinerja baik untuk WeakMap tetapi Chrome tidak begitu baik.
Saya tidak tahu dampak memori, tetapi pola "lingkungan konstruktor" yang beberapa orang peringatkan akan menjadi masalah kinerja sangat bagus.
4 pola dasar adalah:
Data pribadi melalui lingkungan konstruktor
Data pribadi melalui lingkungan konstruktor 2
Data pribadi melalui konvensi penamaan
Data pribadi melalui WeakMaps
Data pribadi melalui simbol
sumber
Saya percaya adalah mungkin untuk mendapatkan 'terbaik dari kedua dunia' menggunakan penutupan di dalam konstruktor. Ada dua variasi:
Semua anggota data bersifat pribadi
Beberapa anggota bersifat pribadi
CATATAN: Ini diakui jelek. Jika Anda tahu solusi yang lebih baik, harap edit jawaban ini.
sumber
Bahkan dimungkinkan menggunakan Simbol dan Proxy. Anda menggunakan simbol dalam ruang lingkup kelas dan menetapkan dua jebakan dalam proxy: satu untuk prototipe kelas sehingga Reflect.ownKeys (instance) atau Object.getOwnPropertySymbols tidak memberikan simbol Anda, yang lain adalah untuk konstruktor itu sendiri jadi ketika
new ClassName(attrs)
dipanggil, instance dikembalikan akan dicegat dan memiliki simbol properti sendiri diblokir. Berikut kodenya:Reflect.ownKeys()
berfungsi seperti itu:Object.getOwnPropertyNames(myObj).concat(Object.getOwnPropertySymbols(myObj))
itu sebabnya kita perlu jebakan untuk objek-objek ini.sumber
Bahkan naskah tidak dapat melakukannya. Dari dokumentasi mereka :
Tapi ditransfasikan di taman bermain mereka ini memberi:
Jadi kata kunci "pribadi" mereka tidak efektif.
sumber
Datang sangat terlambat ke pesta ini tapi saya menekan pertanyaan OP dalam pencarian jadi ... Ya, Anda dapat memiliki properti pribadi dengan membungkus deklarasi kelas dalam penutupan
Ada contoh bagaimana saya memiliki metode pribadi dalam codepen ini . Dalam cuplikan di bawah ini, kelas Berlangganan memiliki dua fungsi 'pribadi'
process
danprocessCallbacks
. Properti apa pun dapat ditambahkan dengan cara ini dan sifatnya dirahasiakan melalui penggunaan penutupan. Privasi IMO adalah kebutuhan yang langka jika kekhawatiran dipisahkan dengan baik dan Javascript tidak perlu membengkak dengan menambahkan lebih banyak sintaks ketika sebuah penutupan dengan rapi melakukan pekerjaan.Saya suka pendekatan ini karena ini memisahkan masalah dengan baik dan menjaga hal-hal yang benar-benar pribadi. Satu-satunya downside adalah kebutuhan untuk menggunakan 'diri' (atau sesuatu yang serupa) untuk merujuk 'ini' dalam konten pribadi.
sumber
Saya pikir jawaban Benjamin mungkin yang terbaik untuk sebagian besar kasus sampai bahasa itu secara native mendukung variabel pribadi secara eksplisit.
Namun, jika karena alasan tertentu Anda perlu mencegah akses
Object.getOwnPropertySymbols()
, metode yang saya pertimbangkan untuk digunakan adalah melampirkan properti unik, tidak dapat dikonfigurasi, tidak dapat dihitung, tidak dapat ditulis yang dapat digunakan sebagai pengidentifikasi properti untuk setiap objek pada konstruksi (seperti unikSymbol
, jika Anda belum memiliki beberapa properti unik lainnya seperti aid
). Kemudian simpan saja peta variabel 'pribadi' setiap objek menggunakan pengenal itu.Keuntungan potensial dari pendekatan ini daripada menggunakan
WeakMap
adalah waktu akses yang lebih cepat jika kinerja menjadi perhatian.sumber
destroy()
metode yang harus dipanggil dengan menggunakan kode setiap kali sebuah objek perlu dihapus.Ya benar-benar bisa, dan sangat mudah juga. Ini dilakukan dengan mengekspos variabel dan fungsi pribadi Anda dengan mengembalikan grafik objek prototipe dalam konstruktor. Ini bukan hal yang baru, tetapi ambillah sedikit untuk memahami keanggunannya. Cara ini tidak menggunakan cakupan global, atau kelemahan. Ini adalah bentuk refleksi yang dibangun ke dalam bahasa. Tergantung pada bagaimana Anda memanfaatkan ini; seseorang dapat memaksa pengecualian yang menginterupsi tumpukan panggilan, atau mengubur pengecualian sebagai
undefined
. Ini ditunjukkan di bawah ini, dan dapat membaca lebih lanjut tentang fitur ini di sinisumber
sumber
console.log(instance.property)
harus melempar atau memberi Anda tidak terdefinisi, tidak memberi Anda kembali "tes".Cara lain mirip dengan dua yang terakhir diposting
sumber
Sebagian besar jawaban mengatakan itu tidak mungkin, atau mengharuskan Anda untuk menggunakan WeakMap atau Symbol, yang merupakan fitur ES6 yang mungkin membutuhkan polyfill. Namun ada cara lain! Lihat ini:
Saya menyebutnya pola pengakses metode ini . Ide dasarnya adalah bahwa kami memiliki penutup , kunci di dalam penutupan, dan kami membuat objek pribadi (dalam konstruktor) yang hanya dapat diakses jika Anda memiliki kunci .
Jika Anda tertarik, Anda dapat membaca lebih lanjut tentang ini di artikel saya . Menggunakan metode ini, Anda bisa membuat per objek properti yang tidak dapat diakses di luar penutupan. Oleh karena itu, Anda dapat menggunakannya dalam konstruktor atau prototipe, tetapi tidak di tempat lain. Saya belum pernah melihat metode ini digunakan di mana pun, tapi saya pikir ini sangat kuat.
sumber
Lihat jawaban ini untuk solusi 'kelas' yang bersih & sederhana dengan antarmuka pribadi dan publik serta dukungan untuk komposisi
sumber
Saya menemukan solusi yang sangat sederhana, cukup gunakan
Object.freeze()
. Tentu saja masalahnya adalah Anda tidak dapat menambahkan apa pun ke objek nanti.sumber
setName(name) { this.name = name; }
Saya menggunakan pola ini dan selalu berhasil untuk saya
sumber
Sebenarnya adalah mungkin.
1. Pertama, buat kelas dan di konstruktor mengembalikan
_public
fungsi yang dipanggil .2. Dalam
_public
fungsi yang dipanggil lulusthis
referensi (untuk mendapatkan akses ke semua metode pribadi dan alat peraga) , dan semua argumen dariconstructor
(yang akan diteruskannew Names()
).3. Dalam
_public
lingkup fungsi ada jugaNames
kelas dengan akses kethis
(_ini ) referensiNames
kelas privatsumber
Anda dapat mencoba ini https://www.npmjs.com/package/private-members
Paket ini akan menyelamatkan anggota secara instan.
sumber