Kita juga dapat menugaskan suatu metode ke kelas secara keseluruhan. Metode seperti ini disebut static .
Dalam deklarasi kelas, mereka diawali dengan kata kunci static
, seperti ini:
Pengguna kelas { metode statis statis() { peringatan(ini === Pengguna); } } Pengguna.staticMethod(); // BENAR
Itu sebenarnya sama dengan menugaskannya sebagai properti secara langsung:
Pengguna kelas {} } Pengguna.Metode Statis = fungsi() { peringatan(ini === Pengguna); }; Pengguna.staticMethod(); // BENAR
Nilai this
dalam panggilan User.staticMethod()
adalah konstruktor kelas User
itu sendiri (aturan “objek sebelum titik”).
Biasanya, metode statis digunakan untuk mengimplementasikan fungsi-fungsi yang dimiliki oleh kelas secara keseluruhan, tetapi tidak dimiliki oleh objek tertentu di dalamnya.
Misalnya, kita memiliki objek Article
dan memerlukan fungsi untuk membandingkannya.
Solusi alami adalah dengan menambahkan metode statis Article.compare
:
kelas Artikel { konstruktor(judul, tanggal) { this.title = judul; this.tanggal = tanggal; } perbandingan statis(artikelA, artikelB) { kembali artikelA.tanggal - artikelB.tanggal; } } // penggunaan biarkan artikel = [ Artikel baru("HTML", Tanggal baru(2019, 1, 1)), Artikel baru("CSS", Tanggal baru(2019, 0, 1)), Artikel baru("JavaScript", Tanggal baru(2019, 11, 1)) ]; artikel.sort(Artikel.bandingkan); peringatan( artikel[0].judul ); // CSS
Di sini metode Article.compare
berdiri “di atas” artikel, sebagai sarana untuk membandingkannya. Ini bukan metode artikel, melainkan seluruh kelas.
Contoh lainnya adalah apa yang disebut metode “pabrik”.
Katakanlah, kita memerlukan beberapa cara untuk membuat artikel:
Buat berdasarkan parameter yang diberikan ( title
, date
, dll).
Buat artikel kosong dengan tanggal hari ini.
…atau entah bagaimana caranya.
Cara pertama bisa diterapkan oleh konstruktor. Dan untuk yang kedua kita bisa membuat metode statis pada kelasnya.
Seperti Article.createTodays()
di sini:
kelas Artikel { konstruktor(judul, tanggal) { this.title = judul; this.tanggal = tanggal; } statis buatHari Ini() { // ingat, ini = Artikel return new this("Intisari hari ini", new Date()); } } biarkan artikel = Artikel.createTodays(); waspada( artikel.judul ); // Intisari hari ini
Sekarang setiap kali kita perlu membuat intisari hari ini, kita dapat memanggil Article.createTodays()
. Sekali lagi, itu bukan metode artikel, tapi metode seluruh kelas.
Metode statis juga digunakan di kelas terkait database untuk mencari/menyimpan/menghapus entri dari database, seperti ini:
// dengan asumsi Article adalah kelas khusus untuk mengelola artikel // metode statis untuk menghapus artikel berdasarkan id: Artikel.hapus({id: 12345});
Metode statis tidak tersedia untuk objek individual
Metode statis dapat dipanggil pada kelas, bukan pada objek individual.
Misalnya kode seperti itu tidak akan berfungsi:
// ... artikel.createTodays(); /// Kesalahan: article.createTodays bukan sebuah fungsi
Tambahan baru-baru ini
Ini adalah tambahan terbaru pada bahasa ini. Contohnya berfungsi di Chrome terbaru.
Properti statis juga dimungkinkan, terlihat seperti properti kelas reguler, tetapi diawali dengan static
:
kelas Artikel { penerbit statis = "Ilya Kantor"; } alert( Artikel.penerbit ); // Ilya Kantor
Itu sama dengan penugasan langsung ke Article
:
Artikel.penerbit = "Ilya Kantor";
Properti dan metode statis diwariskan.
Misalnya, Animal.compare
dan Animal.planet
pada kode di bawah ini diwariskan dan dapat diakses sebagai Rabbit.compare
dan Rabbit.planet
:
kelas Hewan { planet statis = "Bumi"; konstruktor(nama, kecepatan) { this.speed = kecepatan; ini.nama = nama; } lari(kecepatan = 0) { ini.kecepatan += kecepatan; alert(`${this.name} berjalan dengan kecepatan ${this.speed}.`); } perbandingan statis(hewanA, hewanB) { kembalikan animalA.speed - animalB.speed; } } // Mewarisi dari Hewan kelas Kelinci memperluas Hewan { bersembunyi() { alert(`${nama ini} disembunyikan!`); } } biarkan kelinci = [ Kelinci baru("Kelinci Putih", 10), Kelinci baru("Kelinci Hitam", 5) ]; kelinci.sort(Kelinci.bandingkan); kelinci[0].jalankan(); // Kelinci Hitam berlari dengan kecepatan 5. alert(Kelinci.planet); // Bumi
Sekarang ketika kita memanggil Rabbit.compare
, Animal.compare
yang diwarisi akan dipanggil.
Bagaimana cara kerjanya? Sekali lagi, menggunakan prototipe. Seperti yang mungkin sudah Anda duga, extends
memberi Rabbit
referensi [[Prototype]]
ke Animal
.
Jadi, Rabbit extends Animal
membuat dua referensi [[Prototype]]
:
Fungsi Rabbit
secara prototipe mewarisi fungsi Animal
.
Rabbit.prototype
prototypally mewarisi dari Animal.prototype
.
Hasilnya, pewarisan berfungsi baik untuk metode reguler maupun statis.
Di sini, mari kita periksa dengan kode:
kelas Hewan {} kelas Kelinci memperluas Hewan {} // untuk statika alert(Kelinci.__proto__ === Hewan); // BENAR // untuk metode reguler alert(Kelinci.prototype.__proto__ === Hewan.prototipe); // BENAR
Metode statis digunakan untuk fungsionalitas yang termasuk dalam kelas “secara keseluruhan”. Itu tidak berhubungan dengan contoh kelas konkret.
Misalnya, metode perbandingan Article.compare(article1, article2)
atau metode pabrik Article.createTodays()
.
Mereka diberi label dengan kata static
dalam deklarasi kelas.
Properti statis digunakan ketika kita ingin menyimpan data tingkat kelas, juga tidak terikat pada sebuah instance.
Sintaksnya adalah:
kelas Kelasku { properti statis = ...; metode statis() { ... } }
Secara teknis, deklarasi statis sama dengan menugaskan kelas itu sendiri:
Kelasku.properti = ... Kelas Saya.metode = ...
Properti dan metode statis diwariskan.
Untuk class B extends A
prototipe kelas B
itu sendiri menunjuk ke A
: B.[[Prototype]] = A
. Jadi jika suatu field tidak ditemukan di B
, pencarian dilanjutkan di A
pentingnya: 3
Seperti yang kita ketahui, semua objek biasanya mewarisi dari Object.prototype
dan mendapatkan akses ke metode objek “generik” seperti hasOwnProperty
dll.
Misalnya:
kelas Kelinci { konstruktor(nama) { ini.nama = nama; } } biarkan kelinci = kelinci baru("Rab"); // metode hasOwnProperty berasal dari Object.prototype waspada( kelinci.hasOwnProperty('nama') ); // BENAR
Tetapi jika kita mengejanya secara eksplisit seperti "class Rabbit extends Object"
, maka hasilnya akan berbeda dari "class Rabbit"
yang sederhana?
Apa bedanya?
Berikut ini contoh kode tersebut (tidak berfungsi – mengapa? memperbaikinya?):
kelas Kelinci memperluas Objek { konstruktor(nama) { ini.nama = nama; } } biarkan kelinci = kelinci baru("Rab"); waspada( kelinci.hasOwnProperty('nama') ); // Kesalahan
Pertama, mari kita lihat mengapa kode terakhir tidak berfungsi.
Alasannya menjadi jelas jika kita mencoba menjalankannya. Konstruktor kelas yang mewarisi harus memanggil super()
. Kalau tidak, "this"
tidak akan "didefinisikan".
Jadi inilah perbaikannya:
kelas Kelinci memperluas Objek { konstruktor(nama) { super(); // perlu memanggil konstruktor induk saat mewarisi ini.nama = nama; } } biarkan kelinci = kelinci baru("Rab"); waspada( kelinci.hasOwnProperty('nama') ); // BENAR
Tapi itu belum semuanya.
Bahkan setelah perbaikan, masih ada perbedaan penting antara "class Rabbit extends Object"
dan class Rabbit
.
Seperti yang kita ketahui, sintaks “extends” menyiapkan dua prototipe:
Antara "prototype"
fungsi konstruktor (untuk metode).
Antara fungsi konstruktor itu sendiri (untuk metode statis).
Dalam kasus class Rabbit extends Object
artinya:
kelas Kelinci memperluas Objek {} alert( Kelinci.prototipe.__proto__ === Objek.prototipe ); // (1) benar waspada( Kelinci.__proto__ === Objek ); // (2) benar
Jadi Rabbit
sekarang menyediakan akses ke metode statis Object
melalui Rabbit
, seperti ini:
kelas Kelinci memperluas Objek {} // biasanya kita memanggil Object.getOwnPropertyNames peringatan ( Kelinci.getOwnPropertyNames({a: 1, b: 2})); // a,b
Namun jika kita tidak memiliki extends Object
, maka Rabbit.__proto__
tidak disetel ke Object
.
Berikut demonya:
kelas Kelinci {} alert( Kelinci.prototipe.__proto__ === Objek.prototipe ); // (1) benar waspada( Kelinci.__proto__ === Objek ); // (2) salah (!) alert( Kelinci.__proto__ === Fungsi.prototipe ); // sebagai fungsi apa pun secara default // error, tidak ada fungsi seperti itu di Rabbit peringatan ( Kelinci.getOwnPropertyNames({a: 1, b: 2})); // Kesalahan
Jadi Rabbit
tidak menyediakan akses ke metode statis Object
dalam kasus tersebut.
Ngomong-ngomong, Function.prototype
juga memiliki metode fungsi "generik", seperti call
, bind
, dll. Keduanya pada akhirnya tersedia dalam kedua kasus, karena untuk konstruktor Object
bawaan, Object.__proto__ === Function.prototype
.
Berikut gambarnya:
Jadi, singkatnya, ada dua perbedaan:
kelas Kelinci | kelas Kelinci memperluas Objek |
---|---|
– | perlu memanggil super() di konstruktor |
Rabbit.__proto__ === Function.prototype | Rabbit.__proto__ === Object |