Saya tahu ini akan berhasil:
function Foo() {};
Foo.prototype.talk = function () {
alert('hello~\n');
};
var a = new Foo;
a.talk(); // 'hello~\n'
Tetapi jika saya ingin menelepon
Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly
Saya menemukan beberapa metode untuk membuat Foo.talk
pekerjaan,
Foo.__proto__ = Foo.prototype
Foo.talk = Foo.prototype.talk
Apakah ada cara lain untuk melakukan ini? Saya tidak tahu apakah itu benar. Apakah Anda menggunakan metode kelas atau metode statis dalam kode JavaScript Anda?
javascript
oop
lostyzd
sumber
sumber
Foo.talk = function ...
Foo.walk = function() {}
tidak akan mempengaruhi instansnya , karena tidak pada rantai prototipe. Apakah ada cross-browser metode untuk membuat titik fungsi[[prototype]]
ke fungsiprototype
?this
pointer.Jawaban:
Pertama, ingatlah bahwa JavaScript pada dasarnya adalah bahasa prototipe , bukan bahasa berbasis kelas 1 .
Foo
bukan kelas, ini adalah fungsi, yang merupakan objek. Anda dapat instantiate objek dari fungsi itu menggunakannew
kata kunci yang akan memungkinkan Anda untuk membuat sesuatu yang mirip dengan kelas dalam bahasa OOP standar.Saya sarankan untuk mengabaikan
__proto__
sebagian besar waktu karena memiliki dukungan browser lintas yang buruk, dan alih-alih fokus pada belajar tentang caranyaprototype
kerjanya.Jika Anda memiliki instance objek yang dibuat dari fungsi 2 dan Anda mengakses salah satu anggotanya (metode, atribut, properti, konstanta dll) dengan cara apa pun, akses akan mengalir ke hierarki prototipe sampai salah satu (a) menemukan anggota, atau (b) tidak menemukan prototipe lain.
Hirarki dimulai pada objek yang dipanggil, dan kemudian mencari objek prototipe. Jika objek prototipe memiliki prototipe, itu akan berulang, jika tidak ada prototipe,
undefined
dikembalikan.Sebagai contoh:
Bagi saya sepertinya Anda setidaknya sudah memahami bagian-bagian "dasar" ini, tetapi saya perlu membuatnya eksplisit hanya untuk memastikan.
Dalam JavaScript, semuanya adalah objek 3 .
segala sesuatu adalah objek.
function Foo(){}
tidak hanya mendefinisikan fungsi baru, ia mendefinisikan objek fungsi baru yang dapat diakses menggunakanFoo
.Inilah sebabnya mengapa Anda dapat mengakses
Foo
prototipe denganFoo.prototype
.Yang juga dapat Anda lakukan adalah mengatur lebih banyak fungsi pada
Foo
:Fungsi baru ini dapat diakses menggunakan:
Saya harap sekarang Anda memperhatikan kesamaan antara fungsi pada objek fungsi dan metode statis.
Anggap
f = new Foo();
sebagai membuat instance kelas,Foo.prototype.bar = function(){...}
sebagai mendefinisikan metode bersama untuk kelas, danFoo.baz = function(){...}
sebagai mendefinisikan metode statis publik untuk kelas.ECMAScript 2015 memperkenalkan beragam gula sintaksis untuk deklarasi semacam ini agar lebih mudah diimplementasikan sementara juga lebih mudah dibaca. Oleh karena itu, contoh sebelumnya dapat ditulis sebagai:
yang memungkinkan
bar
disebut sebagai:dan
baz
disebut sebagai:1:
class
adalah "Future Reserved Word" dalam spesifikasi ECMAScript 5 , tetapi ES6 memperkenalkan kemampuan untuk mendefinisikan kelas menggunakanclass
kata kunci.2: pada dasarnya instance kelas yang dibuat oleh konstruktor, tetapi ada banyak perbedaan nuansa yang saya tidak ingin menyesatkan Anda
3: nilai-nilai primitif — yang meliputi
undefined
,,null
boolean, angka, dan string — bukan objek teknis karena mereka adalah implementasi bahasa tingkat rendah. Boolean, angka, dan string masih berinteraksi dengan rantai prototipe seolah-olah mereka objek, jadi untuk keperluan jawaban ini, lebih mudah untuk menganggap mereka "objek" meskipun mereka tidak cukup.sumber
Foo.talk()
. Anda bisa menetapkan itu di konstruktor, jika Anda ingin:this.talk = Foo.talk
- atau, seperti yang Anda perhatikan, dengan menetapkanFoo.prototype.talk = Foo.talk
. Tapi saya tidak yakin ini ide yang bagus - pada prinsipnya, metode instance harus spesifik untuk instance tersebut.Foo.talk()
hanya memanggil fungsi namespaced. Anda akan menggunakannya dalam situasi yang mirip dengan bagaimana metode statis dipanggil dalam bahasa OOP seperti Java / C #. Contoh kasus penggunaan yang baik adalah fungsi sepertiArray.isArray()
.Foo.talk = function ()...
tidak akan tersedia untuk subclass di sana nama kelasnya sendiri. Ini bisa diselesaikan dengan subclass "extending", tapi saya juga masih mencari cara yang lebih elegan.Anda dapat mencapainya seperti di bawah ini:
Anda sekarang dapat menjalankan fungsi "bicara" seperti di bawah ini:
Anda dapat melakukan ini karena dalam JavaScript, fungsi juga merupakan objek.
sumber
Panggil metode statis dari sebuah instance:
Proyek Kelas Javascript Sederhana: https://github.com/reduardo7/sjsClass
sumber
Clazz.staticMethod
tetapi ia menunjukkan kepada Anda cara menautkan metode statis ini dari dalam objek yang dipakai. Ini sangat berguna di lingkungan seperti Node.js di mana, menggunakan mengharuskan, Anda mungkin tidak memiliki akses langsung ke konstruktor asli. Satu-satunya hal yang akan saya tambahkan adalahthis.constructor.staticMethod.apply(this, arguments);
constructor: (a) -> @constructor.add @
(yah hampir, pokoknya)Berikut adalah contoh yang baik untuk menunjukkan bagaimana Javascript bekerja dengan variabel / instance variabel dan metode.
sumber
this
.this
kata kunciSelain itu, sekarang mungkin dilakukan dengan
class
danstatic
akan memberi
sumber
a.talk()
tidak berhasil. Jawaban yang diterima mengatakan rantai prototipe harus menemukannya, kan? Tapi itu tidak terjadiSaya menggunakan ruang nama:
Dan untuk menggunakannya:
Atau
sumber
ES6 mendukung sekarang
class
&static
kata kunci seperti pesona:sumber
Jika Anda harus menulis metode statis di ES5, saya menemukan tutorial yang bagus untuk itu:
lihat @ https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/
sumber
Catatan tambahan saja. Menggunakan kelas ES6, Ketika kita membuat metode statis .. mesin Javacsript mengatur atribut deskriptor sedikit berbeda dari metode "statis" old-school
itu menetapkan atribut internal (properti deskriptor) untuk merek () menjadi
dibandingkan dengan
yang menetapkan atribut internal untuk merek () ke
lihat bahwa enumerable disetel ke false untuk metode statis di ES6.
itu berarti Anda tidak dapat menggunakan loop masuk untuk memeriksa objek
Metode statis di ES6 diperlakukan seperti milik pribadi kelas lain (nama, panjang, konstruktor) kecuali bahwa metode statis masih dapat ditulis sehingga deskriptor yang dapat ditulis diatur ke true
{ writable: true }
. itu juga berarti bahwa kita dapat menimpanyasumber
Ketika Anda mencoba menelepon
Foo.talk
, JS mencoba mencari fungsitalk
melalui__proto__
dan, tentu saja, itu tidak dapat ditemukan.Foo.__proto__
adalahFunction.prototype
.sumber
Panggilan metode statis dilakukan langsung di kelas dan tidak dapat dipanggil pada instance kelas. Metode statis sering digunakan untuk membuat fungsi utilitas
Deskripsi yang cukup jelas
Diambil Langsung dari mozilla.org
Foo perlu terikat ke kelas Anda Kemudian ketika Anda membuat contoh baru Anda dapat memanggil myNewInstance.foo () Jika Anda mengimpor kelas Anda, Anda dapat memanggil metode statis
sumber
Ketika saya menghadapi situasi seperti itu, saya telah melakukan sesuatu seperti ini:
jadi sekarang saya dapat memanggil metode info sebagai
Logger.info("my Msg", "Tag");
sumber
Dalam kasus Anda, jika Anda ingin
Foo.talk()
:Tapi ini cara yang tidak efisien untuk diterapkan, menggunakan
prototype
lebih baik.Cara lain, Cara saya didefinisikan sebagai kelas statis:
Kelas statis di atas tidak perlu digunakan
prototype
karena hanya akan dibangun sekali sebagai penggunaan statis.sumber
Javascript tidak memiliki kelas yang sebenarnya melainkan menggunakan sistem pewarisan prototypal di mana objek 'mewarisi' dari objek lain melalui rantai prototipe mereka. Ini paling baik dijelaskan melalui kode itu sendiri:
sumber