Saat ini di ES5 banyak dari kita menggunakan pola berikut dalam kerangka kerja untuk membuat kelas dan variabel kelas, yang nyaman:
// ES 5
FrameWork.Class({
variable: 'string',
variable2: true,
init: function(){
},
addItem: function(){
}
});
Di ES6 Anda dapat membuat kelas secara native, tetapi tidak ada opsi untuk memiliki variabel kelas:
// ES6
class MyClass {
const MY_CONST = 'string'; // <-- this is not possible in ES6
constructor(){
this.MY_CONST;
}
}
Sayangnya, hal di atas tidak akan berhasil, karena hanya kelas yang bisa berisi metode.
Saya mengerti bahwa saya bisa this.myVar = true
masuk constructor
... tapi saya tidak ingin 'membuang' konstruktor saya, terutama ketika saya memiliki 20-30 + params untuk kelas yang lebih besar.
Saya sedang memikirkan banyak cara untuk menangani masalah ini, tetapi belum menemukan yang bagus. (Misalnya: membuat ClassConfig
handler, dan meneruskan parameter
objek, yang dideklarasikan secara terpisah dari kelas. Kemudian handler akan melampirkan ke kelas. WeakMaps
Entah bagaimana saya juga mengintegrasikan, entah bagaimana.)
Gagasan apa yang akan Anda miliki untuk menangani situasi ini?
sumber
this.member = member
di konstruktor Anda dengan 20-30 parameter?public variable2 = true
bawah kelas saja? Ini akan mendefinisikannya pada prototipe.Jawaban:
Pembaruan 2018:
Sekarang ada proposal tahap 3 - Saya berharap untuk membuat jawaban ini menjadi usang dalam beberapa bulan.
Sementara itu siapa pun yang menggunakan TypeScript atau babel dapat menggunakan sintaks:
Di dalam badan deklarasi / ekspresi kelas dan itu akan mendefinisikan variabel. Semoga dalam beberapa bulan / minggu saya dapat memposting pembaruan.
Pembaruan: Chrome 74 sekarang hadir dengan sintaks ini berfungsi.
Catatan dalam wiki ES untuk proposal dalam ES6 ( kelas maksimal minimal ) catatan:
Ini berarti bahwa apa yang Anda minta dipertimbangkan, dan secara eksplisit memutuskan untuk tidak melakukannya.
tapi kenapa?
Pertanyaan bagus. Orang-orang baik di TC39 menginginkan deklarasi kelas untuk mendeklarasikan dan mendefinisikan kemampuan suatu kelas. Bukan anggotanya. Deklarasi kelas ES6 mendefinisikan kontraknya untuk penggunanya.
Ingat, definisi kelas mendefinisikan metode prototipe - mendefinisikan variabel pada prototipe umumnya bukan sesuatu yang Anda lakukan. Anda tentu saja dapat menggunakan:
Di konstruktor seperti yang Anda sarankan. Lihat juga ringkasan konsensus .
ES7 dan selanjutnya
Proposal baru untuk ES7 sedang dikerjakan yang memungkinkan variabel instance yang lebih ringkas melalui deklarasi dan ekspresi kelas - https://esdiscuss.org/topic/es7-property-initializers
sumber
static
propertistatic
hanya berfungsi untuk metode.Hanya untuk menambah jawaban Benjamin - variabel kelas dimungkinkan, tetapi Anda tidak akan menggunakannya
prototype
untuk mengaturnya.Untuk variabel kelas sejati, Anda ingin melakukan sesuatu seperti berikut:
Dari dalam metode kelas variabel itu dapat diakses sebagai
this.constructor.foo
(atauMyClass.foo
).Properti kelas ini biasanya tidak dapat diakses dari ke instance kelas. yaitu
MyClass.foo
memberi'bar'
tapinew MyClass().foo
adalahundefined
Jika Anda juga ingin memiliki akses ke variabel kelas Anda dari instance, Anda juga harus mendefinisikan pengambil:
Saya hanya menguji ini dengan Traceur, tetapi saya percaya ini akan bekerja sama dalam implementasi standar.
JavaScript tidak benar-benar memiliki kelas . Bahkan dengan ES6 kita melihat bahasa berbasis objek atau prototipe daripada bahasa berbasis kelas. Dalam hal apa pun
function X () {}
,X.prototype.constructor
poin kembali keX
. Ketikanew
operator digunakanX
, objek baru dibuat mewarisiX.prototype
. Setiap properti yang tidak terdefinisi di objek baru itu (termasukconstructor
) dilihat dari sana. Kita dapat menganggap ini sebagai menghasilkan objek dan properti kelas.sumber
Babel mendukung variabel kelas di ESNext, periksa contoh ini :
sumber
Dalam contoh Anda:
Karena MY_CONST adalah primitif https://developer.mozilla.org/en-US/docs/Glossary/Primitive yang bisa kita lakukan:
Tetapi jika
MY_CONST
tipe referensi sepertistatic get MY_CONST() {return ['string'];}
keluaran peringatan adalah string, false . Dalam hal inidelete
operator dapat melakukan trik:Dan akhirnya untuk variabel kelas tidak
const
:sumber
delete
operator, jika sendirian karena alasan kinerja. Apa yang sebenarnya Anda inginkan di sini adalahObject.defineProperty
.Karena masalah Anda sebagian besar bergaya (tidak ingin mengisi konstruktor dengan banyak deklarasi), itu dapat diselesaikan dengan gaya juga.
Cara saya melihatnya, banyak bahasa berbasis kelas memiliki konstruktor menjadi fungsi yang dinamai dengan nama kelas itu sendiri. Secara gaya kita dapat menggunakannya untuk membuat kelas ES6 yang secara gaya masih masuk akal tetapi tidak mengelompokkan tindakan khas yang terjadi di konstruktor dengan semua deklarasi properti yang kami lakukan. Kami cukup menggunakan konstruktor JS aktual sebagai "area deklarasi", lalu membuat fungsi kelas bernama yang sebaliknya kami perlakukan sebagai area "konstruktor lain", menyebutnya di akhir konstruktor yang sebenarnya.
Keduanya akan disebut sebagai instance baru dibangun.
Agak seperti memiliki 2 konstruktor di mana Anda memisahkan deklarasi dan tindakan konstruktor lain yang ingin Anda ambil, dan secara gaya membuatnya tidak terlalu sulit untuk memahami apa yang sedang terjadi juga.
Saya menemukan itu adalah gaya yang baik untuk digunakan ketika berhadapan dengan banyak deklarasi dan / atau banyak tindakan yang perlu terjadi pada instantiasi dan ingin menjaga dua ide berbeda satu sama lain.
CATATAN : Saya sangat sengaja tidak menggunakan ide idiomatik khas "menginisialisasi" (seperti metode
init()
atauinitialize()
) karena mereka sering digunakan secara berbeda. Ada semacam perbedaan dugaan antara gagasan membangun dan menginisialisasi. Bekerja dengan konstruktor, orang-orang tahu bahwa mereka dipanggil secara otomatis sebagai bagian dari Instansiasi. Melihatinit
metode yang akan diasumsikan oleh banyak orang tanpa pandangan kedua bahwa mereka perlu melakukan sesuatu dalam bentukvar mc = MyClass(); mc.init();
, karena itulah cara Anda biasanya menginisialisasi. Aku tidak mencoba untuk menambahkan proses inisialisasi untuk pengguna kelas, aku mencoba untuk menambahkan ke proses pembangunan kelas itu sendiri.Sementara beberapa orang mungkin melakukan pengambilan ganda untuk sesaat, itu sebenarnya intinya: itu menyampaikan kepada mereka bahwa maksudnya adalah bagian dari konstruksi, bahkan jika itu membuat mereka melakukan sedikit pengambilan ganda dan pergi "itu bukan bagaimana konstruktor ES6 bekerja "dan luangkan waktu sejenak melihat konstruktor yang sebenarnya untuk pergi" oh, mereka menyebutnya di bagian bawah, saya mengerti ", itu jauh lebih baik daripada TIDAK mengomunikasikan maksud itu (atau salah mengomunikasikannya) dan mungkin mendapatkan banyak orang menggunakannya salah, mencoba menginisialisasi dari luar dan sampah. Itu sangat disengaja dengan pola yang saya sarankan.
Bagi mereka yang tidak ingin mengikuti pola itu, kebalikannya bisa juga. Perkuat deklarasi ke fungsi lain di awal. Mungkin nama itu "properti" atau "properti publik" atau sesuatu. Kemudian letakkan sisanya di konstruktor normal.
Perhatikan bahwa metode kedua ini mungkin terlihat lebih bersih tetapi juga memiliki masalah yang melekat di mana
properties
akan ditimpa karena satu kelas menggunakan metode ini meluas yang lain. Anda harus memberikan lebih banyak nama unikproperties
untuk menghindari hal itu. Metode pertama saya tidak memiliki masalah ini karena setengah palsu dari konstruktor secara unik dinamai setelah kelas.sumber
init
.init
adalah pola yang sering digunakan, dan sering dimaksudkan untuk dipanggil dari luar kelas ketika pengguna luar ingin menginisialisasi, yaituvar b = new Thing(); b.init();
. Ini adalah pilihan gaya 100% yang saya lebih suka untuk berkomunikasi bahwa itu adalah fungsi ke-2 yang secara otomatis dipanggil dengan mengambil keuntungan dari pola yang ditemukan dalam bahasa lain. Jauh lebih kecil kemungkinannya seseorang akan melihat ini dan menganggap bahwa mereka perlu memanggilMyClass
metode dari luar, lebih mungkin bahwa mereka akan menyadari maksudnya adalah metode ke-2 yang bertindak dalam konstruksi (yaitu dipanggil dengan sendirinya pada instantiasi).MyClass
.$myvar
cara standar untuk merujuk ke variabel yang dimaksudkan untuk menampung objek jQuery tidak nyaman mirip dengan pola memiliki $ pada awal variabel yang digunakan oleh begitu banyak programmer PHP. Hanya sedikit implikasi bahwa "ya, itu bukan hal yang persis sama ... tapi lihat ... itu masih variabel karena itu adalah cara variabel dilakukan dalam beberapa bahasa!" membantu.properties()
fungsi. Namun, hal-hal menjadi sedikit lebih rumit ketika memperluas kelas jadi saya akan menyarankan bahwa jika Anda menggunakanproperties()
fungsi di semua kelas Anda untuk mendeklarasikan Anda properti kelas yang Anda awali nama metode dengan nama kelas (IE:MyClassProperties()
untuk menghindari overriding tanpa sengaja panggilan fungsi di dalam sub kelas. Juga, perlu diingat bahwa panggilan apa punsuper()
harus dideklarasikan terlebih dahulu di konstruktor kelas.Bagaimana dengan cara oldschool?
Dalam konstruktor Anda hanya menyebutkan vars yang harus dihitung. Saya suka warisan prototipe untuk fitur ini - ini dapat membantu menghemat banyak memori (kalau-kalau ada banyak vars yang tidak pernah ditugaskan).
sumber
Seperti yang dikatakan Benjamin dalam jawabannya, TC39 secara eksplisit memutuskan untuk tidak menyertakan fitur ini setidaknya untuk ES2015. Namun, konsensus tampaknya bahwa mereka akan menambahkannya di ES2016.
Sintaksnya belum diputuskan, tetapi ada proposal awal untuk ES2016 yang akan memungkinkan Anda untuk mendeklarasikan properti statis di kelas.
Berkat keajaiban babel, Anda dapat menggunakannya hari ini. Aktifkan transformasi properti kelas sesuai dengan instruksi ini dan Anda siap melakukannya. Berikut ini contoh sintaksnya:
Proposal ini dalam kondisi sangat awal, jadi bersiaplah untuk mengubah sintaks Anda seiring berjalannya waktu.
sumber
[Utas panjang, tidak yakin apakah sudah terdaftar sebagai opsi ...].
Sebuah sederhana alternatif untuk contsants hanya , akan mendefinisikan luar const kelas. Ini akan dapat diakses hanya dari modul itu sendiri, kecuali disertai dengan pengambil.
Cara
prototype
ini tidak dikotori dan Anda mendapatkanconst
.sumber
var
bukannyaconst
2) menggunakan beberapa instance kelas ini? Kemudian variabel eksternal akan diubah dengan setiap instance dari kelasES7
sintaks anggota kelas:ES7
memiliki solusi untuk 'membuang sampah' fungsi konstruktor Anda. Berikut ini sebuah contoh:Contoh di atas akan terlihat sebagai berikut
ES6
:Berhati-hatilah saat menggunakan ini bahwa sintaks ini mungkin tidak didukung oleh semua browser dan mungkin harus ditransmisikan ke versi JS yang lebih lama.
Bonus: pabrik objek:
sumber
Anda dapat meniru perilaku kelas es6 ... dan menggunakan variabel kelas Anda :)
Saya menaruhnya di GitHub
sumber
Cara saya memecahkan ini, yang merupakan pilihan lain (jika Anda memiliki jQuery tersedia), adalah untuk Menentukan bidang dalam objek old-school dan kemudian memperluas kelas dengan objek itu. Saya juga tidak ingin membumbui konstruktor dengan tugas, ini tampaknya menjadi solusi yang rapi.
- Perbarui Mengikuti komentar Bergi.
Tidak Ada Versi JQuery:
Anda masih berakhir dengan konstruktor 'gemuk', tetapi setidaknya semuanya dalam satu kelas dan ditugaskan dalam satu pukulan.
EDIT # 2: Sekarang saya sudah menjadi lingkaran penuh dan sekarang saya memberikan nilai dalam konstruktor, misalnya
Mengapa? Sederhana banget, menggunakan komentar JSdoc di atas ditambah beberapa, PHPStorm mampu melakukan penyelesaian kode pada properti. Menetapkan semua vars dalam satu pukulan bagus, tetapi ketidakmampuan untuk menyelesaikan kode properti, imo, tidak sebanding dengan manfaat kinerja (hampir pasti sangat kecil).
sumber
class
sintaks, Anda juga dapat melakukannyaObject.assign
. Tidak perlu jQuery.MyClassFields
konstruktor - tidak ada metode. Bisakah Anda menguraikan mengapa Anda melakukan ini (alih-alih, katakanlah, fungsi pabrik sederhana yang mengembalikan objek literal)?Anda dapat mendeklarasikan variabel di dalam konstruktor.
sumber
Tetap saja Anda tidak dapat mendeklarasikan kelas seperti di bahasa pemrograman lain. Tetapi Anda bisa membuat banyak variabel kelas. Tetapi masalah adalah ruang lingkup objek kelas. Jadi Menurut saya, Cara terbaik Pemrograman OOP di ES6 Javascript: -
sumber
Ini adalah kombo agak statis statis dan mendapatkan pekerjaan untuk saya
digunakan di tempat lain
sumber
singleton_instance
sebagai nama properti sehingga semua orang mengerti apa yang Anda lakukan di sini.