Apa bedanya
var A = function () {
this.x = function () {
//do something
};
};
dan
var A = function () { };
A.prototype.x = function () {
//do something
};
javascript
prototype
this
sw234
sumber
sumber
a1.x !== a2.x
:; pada prototipe:a1.x === a2.x
Jawaban:
Contoh-contoh tersebut memiliki hasil yang sangat berbeda.
Sebelum melihat perbedaannya, hal-hal berikut harus diperhatikan:
[[Prototype]]
properti pribadi instans .myObj.method()
) maka ini dalam metode referensi objek. Di mana ini tidak diatur oleh panggilan atau oleh penggunaan bind , itu default ke objek global (jendela di browser) atau dalam mode ketat, tetap tidak ditentukan.Jadi inilah cuplikan yang dimaksud:
Dalam hal ini, variabel
A
diberi nilai yang merupakan referensi ke suatu fungsi. Ketika fungsi itu disebut menggunakanA()
, fungsi ini tidak diatur oleh panggilan sehingga default ke objek global dan ekspresithis.x
efektifwindow.x
. Hasilnya adalah referensi ke ekspresi fungsi di sisi kanan ditugaskanwindow.x
.Dalam kasus:
sesuatu yang sangat berbeda terjadi. Di baris pertama, variabel
A
ditugaskan referensi ke suatu fungsi. Dalam JavaScript, semua objek fungsi memiliki properti prototipe secara default sehingga tidak ada kode terpisah untuk membuat objek A.prototype .Di baris kedua, A.prototype.x diberikan referensi ke suatu fungsi. Ini akan membuat properti x jika tidak ada, atau menetapkan nilai baru jika itu ada. Jadi perbedaannya dengan contoh pertama di mana properti x objek terlibat dalam ekspresi.
Contoh lain di bawah ini. Ini mirip dengan yang pertama (dan mungkin apa yang ingin Anda tanyakan):
Dalam contoh ini,
new
operator telah ditambahkan sebelum ekspresi fungsi sehingga fungsi tersebut disebut sebagai konstruktor. Ketika dipanggil dengannew
, fungsi ini diatur untuk referensi Obyek baru yang[[Prototype]]
milik pribadinya ditetapkan untuk referensi prototipe publik konstruktor . Jadi dalam pernyataan penugasan,x
properti akan dibuat pada objek baru ini. Ketika dipanggil sebagai konstruktor, fungsi mengembalikan objek ini secara default, jadi tidak perlu untukreturn this;
pernyataan yang terpisah .Untuk memeriksa bahwa A memiliki properti x :
Ini adalah penggunaan baru yang tidak biasa karena satu-satunya cara untuk merujuk konstruktor adalah melalui A.constructor . Akan lebih umum dilakukan:
Cara lain untuk mencapai hasil yang serupa adalah dengan menggunakan ekspresi fungsi yang langsung dipanggil:
Dalam hal ini,
A
tetapkan nilai balik dari memanggil fungsi di sisi kanan. Di sini sekali lagi, karena ini tidak diatur dalam panggilan, itu akan merujuk objek global danthis.x
efektifwindow.x
. Karena fungsi tidak mengembalikan apa pun,A
akan memiliki nilaiundefined
.Perbedaan antara kedua pendekatan ini juga bermanifestasi jika Anda membuat cerita bersambung dan menghapus serialkan objek Javascript ke / dari JSON. Metode yang didefinisikan pada prototipe objek tidak diserialisasi ketika Anda membuat serial objek, yang mungkin nyaman ketika misalnya Anda ingin membuat serial hanya bagian data dari suatu objek, tetapi tidak metode itu:
Pertanyaan terkait :
Sidenote: Mungkin tidak ada penghematan memori yang signifikan antara kedua pendekatan, namun menggunakan prototipe untuk berbagi metode dan properti kemungkinan akan menggunakan lebih sedikit memori daripada setiap contoh memiliki salinannya sendiri.
JavaScript bukan bahasa tingkat rendah. Mungkin tidak terlalu berharga untuk memikirkan prototyping atau pola pewarisan lainnya sebagai cara untuk secara eksplisit mengubah cara memori dialokasikan.
sumber
null
), tetapi ini sangat berbeda dariprototype
properti - yang ada di fungsi dan yang prototipe dari semua instance diatur ketika mereka dibangun dengannew
. Tidak percaya ini benar-benar mendapat 87 upvotes :-("The language is functional"
apakah Anda yakin bahwa ini adalah arti fungsional?A
sebagai fungsi, dan setengah lainnya adalah tentang cara-cara yang tidak jelas dan tidak lazim untuk dilakukan. sesuatu yang langsung.Seperti yang orang lain katakan versi pertama, menggunakan "ini" menghasilkan setiap instance dari kelas A yang memiliki salinan independen sendiri dari metode fungsi "x". Sedangkan menggunakan "prototipe" akan berarti bahwa setiap instance dari kelas A akan menggunakan salinan metode "x" yang sama.
Berikut adalah beberapa kode untuk menunjukkan perbedaan halus ini:
Seperti yang telah disebutkan orang lain, ada berbagai alasan untuk memilih satu metode atau yang lain. Sampel saya hanya dimaksudkan untuk menunjukkan perbedaan secara jelas.
sumber
this
objek, yang merupakan pemilik metode. yaitu metode tidak memiliki objek yang merupakan pemiliknya. Dalam hal ini adathis
objek, seperti yang ditunjukkan di kelas A dalam contoh.Ambil 2 contoh ini:
vs.
Kebanyakan orang di sini (terutama jawaban berperingkat teratas) mencoba menjelaskan bagaimana mereka berbeda tanpa menjelaskan MENGAPA. Saya pikir ini salah dan jika Anda memahami dasar-dasarnya terlebih dahulu, perbedaannya akan menjadi jelas. Mari kita coba jelaskan dasarnya dulu ...
a) Fungsi adalah objek dalam JavaScript. SETIAP objek dalam JavaScript mendapat properti internal (artinya, Anda tidak dapat mengaksesnya seperti properti lain, kecuali mungkin di browser seperti Chrome), sering disebut sebagai
__proto__
(Anda sebenarnya dapat mengetikanyObject.__proto__
di Chrome untuk melihat apa yang dirujuk. Ini hanya itu , properti, tidak lebih. Properti dalam JavaScript = variabel di dalam objek, tidak lebih. Apa yang dilakukan variabel? Mereka menunjukkan sesuatu.Jadi apa yang
__proto__
ditunjukkan properti ini ? Ya, biasanya objek lain (kami akan jelaskan alasannya nanti). Satu-satunya cara untuk memaksa JavaScript agar__proto__
properti TIDAK menunjuk ke objek lain adalah dengan menggunakannyavar newObj = Object.create(null)
. Bahkan jika Anda melakukan ini,__proto__
properti MASIH ada sebagai properti objek, hanya saja tidak menunjuk ke objek lain, itu menunjuk kenull
.Di sinilah kebanyakan orang menjadi bingung:
Ketika Anda membuat fungsi baru dalam JavaScript (yang juga merupakan objek, ingat?), Saat itu didefinisikan, JavaScript secara otomatis membuat properti baru pada fungsi yang disebut
prototype
. Cobalah:A.prototype
BENAR - BENAR BERBEDA dari__proto__
properti. Dalam contoh kami, 'A' sekarang memiliki DUA properti yang disebut 'prototipe' dan__proto__
. Ini adalah kebingungan besar bagi orang-orang.prototype
dan__proto__
properti sama sekali tidak terkait, mereka hal-hal yang terpisah yang menunjuk ke nilai yang terpisah.Anda mungkin bertanya-tanya: Mengapa JavaScript memiliki
__proto__
properti yang dibuat pada setiap objek? Satu kata: delegasi . Ketika Anda memanggil properti pada objek dan objek tidak memilikinya, maka JavaScript mencari objek yang direferensikan__proto__
untuk melihat apakah mungkin memilikinya. Jika tidak memilikinya, maka terlihat pada__proto__
properti objek itu dan seterusnya ... hingga rantai berakhir. Demikianlah nama rantai prototipe . Tentu saja jika__proto__
tidak menunjuk ke objek dan malah menunjuk kenull
, semoga beruntung, JavaScript menyadari itu dan akan mengembalikan Andaundefined
untuk properti.Anda mungkin juga bertanya-tanya, mengapa JavaScript membuat properti yang dipanggil
prototype
untuk suatu fungsi ketika Anda mendefinisikan fungsinya? Karena itu mencoba membodohi Anda, ya menipu Anda bahwa itu bekerja seperti bahasa berbasis kelas.Mari kita lanjutkan dengan contoh kita dan membuat "objek" dari
A
:Ada sesuatu yang terjadi di latar belakang ketika hal ini terjadi.
a1
adalah variabel biasa yang diberi objek kosong baru.Fakta bahwa Anda menggunakan operator
new
sebelum pemanggilan fungsiA()
melakukan sesuatu TAMBAHAN di latar belakang. Katanew
kunci membuat objek baru yang sekarang referensia1
dan objek itu kosong. Inilah yang terjadi sebagai tambahan:Kami mengatakan bahwa pada setiap definisi fungsi ada properti baru yang dibuat bernama
prototype
(yang dapat Anda akses, tidak seperti dengan__proto__
properti) yang dibuat? Nah, properti itu sedang digunakan sekarang.Jadi kita sekarang pada titik di mana kita memiliki
a1
objek kosong yang baru dipanggang . Kami mengatakan bahwa semua objek dalam JavaScript memiliki__proto__
properti internal yang menunjuk ke sesuatu (a1
juga memilikinya), apakah itu null atau objek lain. Apa yang dilakukan olehnew
operator adalah menetapkan__proto__
properti itu untuk menunjuk keprototype
properti fungsi . Baca lagi. Ini pada dasarnya ini:Kami mengatakan bahwa
A.prototype
tidak lebih dari objek kosong (kecuali kami mengubahnya ke sesuatu yang lain sebelum mendefinisikana1
). Jadi sekarang pada dasarnyaa1.__proto__
menunjuk ke hal yang samaA.prototype
menunjuk ke, yaitu objek kosong itu. Keduanya menunjuk ke objek yang sama yang dibuat ketika baris ini terjadi:Sekarang, ada hal lain yang terjadi ketika
var a1 = new A()
pernyataan diproses. Pada dasarnyaA()
dieksekusi dan jika A adalah sesuatu seperti ini:Semua hal di dalam
function() { }
akan dieksekusi. Ketika Anda mencapaithis.hey..
garis,this
diubah kea1
dan Anda mendapatkan ini:Saya tidak akan membahas mengapa
this
perubahana1
tetapi ini adalah jawaban yang bagus untuk mempelajari lebih lanjut.Jadi untuk meringkas, ketika Anda melakukannya
var a1 = new A()
ada 3 hal yang terjadi di latar belakang:a1
.a1 = {}
a1.__proto__
properti ditugaskan untuk menunjuk pada hal yang sama denganA.prototype
menunjuk ke (objek kosong lain {})Fungsi
A()
ini dieksekusi denganthis
set ke objek kosong baru yang dibuat pada langkah 1 (baca jawaban yang saya rujuk di atas tentang mengapathis
perubahana1
)Sekarang, mari kita coba membuat objek lain:
Langkah 1,2,3 akan diulang. Apakah Anda memperhatikan sesuatu? Kata kuncinya adalah repeat. Langkah 1:
a2
akan menjadi objek kosong baru, langkah 2:__proto__
propertinya akan menunjuk ke hal yang samaA.prototype
dan yang paling penting, langkah 3: fungsiA()
LAGI dieksekusi, yang berarti bahwaa2
akan mendapatkanhey
properti yang mengandung fungsi.a1
dana2
memiliki dua properti SEPARATE bernamahey
yang mengarah ke 2 fungsi SEPARATE! Kami sekarang memiliki fungsi duplikat dalam dua objek yang berbeda melakukan hal yang sama, oops ... Anda dapat membayangkan implikasi memori ini jika kami memiliki 1000 objek yang dibuat dengannew A
, setelah semua fungsi deklarasi mengambil lebih banyak memori daripada sesuatu seperti angka 2. Jadi bagaimana kita mencegah ini?Ingat mengapa
__proto__
properti ada di setiap objek? Sehingga jika Anda mengambilyoMan
properti padaa1
(yang tidak ada),__proto__
propertinya akan dikonsultasikan, yang jika itu adalah objek (dan sebagian besar kasusnya adalah), ia akan memeriksa apakah itu berisiyoMan
, dan jika tidak, itu akan berkonsultasi dengan objek itu__proto__
dll. Jika ya, ia akan mengambil nilai properti itu dan menampilkannya kepada Anda.Jadi seseorang memutuskan untuk menggunakan fakta ini + fakta bahwa ketika Anda membuat
a1
,__proto__
propertinya menunjuk ke objek yang sama (kosong)A.prototype
menunjuk ke dan melakukan ini:Keren! Sekarang, ketika Anda membuat
a1
, itu lagi melewati semua 3 langkah di atas, dan pada langkah 3, itu tidak melakukan apa-apa, karenafunction A()
tidak ada yang dieksekusi. Dan jika kita melakukannya:Ini akan melihat yang
a1
tidak mengandunghey
dan akan memeriksa nya__proto__
objek propertinya untuk melihat apakah memilikinya, yang merupakan kasusnya.Dengan pendekatan ini kami menghilangkan bagian dari langkah 3 di mana fungsi diduplikasi pada setiap pembuatan objek baru. Alih-alih
a1
dana2
memilikihey
properti terpisah , sekarang NONE dari mereka memilikinya. Yang, kurasa, kau sudah tahu sendiri sekarang. Itu hal yang baik ... jika Anda mengerti__proto__
danFunction.prototype
, pertanyaan seperti ini akan sangat jelas.CATATAN: Beberapa orang cenderung tidak menyebut properti Prototipe internal sebagai
__proto__
, Saya telah menggunakan nama ini melalui pos untuk membedakannya dengan jelas denganFunctional.prototype
properti sebagai dua hal yang berbeda.sumber
__proto__
dan.prototype
adalah hal yang sangat berbeda.Dalam kebanyakan kasus mereka pada dasarnya sama, tetapi versi kedua menyimpan memori karena hanya ada satu contoh fungsi alih-alih fungsi terpisah untuk setiap objek.
Alasan untuk menggunakan formulir pertama adalah untuk mengakses "anggota pribadi". Sebagai contoh:
Karena aturan pelingkupan javascript, private_var tersedia untuk fungsi yang ditetapkan untuk this.x, tetapi tidak di luar objek.
sumber
Contoh pertama mengubah antarmuka untuk objek itu saja. Contoh kedua mengubah antarmuka untuk semua objek dari kelas itu.
sumber
x
tersedia untuk semua objek yang prototipenya diberikan contoh baru dari A:function B () {}; B.prototype = new A(); var b = new B(); b.x() // Will call A.x if A is defined by first example;
Masalah utama dengan menggunakan
this
alih-alihprototype
adalah ketika menimpa metode, konstruktor dari kelas dasar masih akan merujuk pada metode yang diganti. Pertimbangkan ini:melawan:
Jika Anda pikir ini bukan masalah, maka itu tergantung pada apakah Anda bisa hidup tanpa variabel pribadi, dan apakah Anda cukup berpengalaman untuk mengetahui kebocoran saat Anda melihatnya. Juga, harus meletakkan logika konstruktor setelah definisi metode tidak nyaman.
melawan:
sumber
Setiap objek terkait dengan objek prototipe. Saat mencoba mengakses properti yang tidak ada, JavaScript akan mencari objek prototipe objek untuk properti itu dan mengembalikannya jika ada.
The
prototype
milik konstruktor fungsi mengacu pada objek prototipe dari semua contoh dibuat dengan fungsi yang ketika menggunakannew
.Dalam contoh pertama Anda, Anda menambahkan properti
x
ke setiap instance yang dibuat denganA
fungsi.Dalam contoh kedua Anda menambahkan properti ke objek prototipe yang dibuat semua
A
titik dengan menunjuk.Sebagai kesimpulan, dalam contoh pertama salinan fungsi ditugaskan untuk setiap contoh . Dalam contoh kedua, satu salinan fungsi dibagikan oleh semua instance .
sumber
Apa bedanya? => Banyak.
Saya pikir,
this
versi ini digunakan untuk mengaktifkan enkapsulasi, yaitu penyembunyian data. Ini membantu untuk memanipulasi variabel pribadi.Mari kita lihat contoh berikut:
Sekarang,
prototype
struktur dapat diterapkan sebagai berikut:Orang dewasa yang berbeda memiliki usia yang berbeda, tetapi semua orang dewasa mendapatkan hak yang sama.
Jadi, kami menambahkannya menggunakan prototipe, bukan ini.
Mari kita lihat implementasinya sekarang.
Semoga ini membantu.
sumber
Prototipe adalah templat kelas; yang berlaku untuk semua contoh masa depan itu. Padahal ini adalah contoh khusus dari objek.
sumber
Saya tahu ini telah dijawab sampai mati tetapi saya ingin menunjukkan contoh nyata perbedaan kecepatan.
Di sini kami membuat 2.000.000 objek baru dengan
print
metode di Chrome. Kami menyimpan setiap objek dalam array. Memakaiprint
prototipe membutuhkan sekitar 1/2 selama.sumber
Biarkan saya memberi Anda jawaban yang lebih komprehensif yang saya pelajari selama kursus pelatihan JavaScript.
Sebagian besar jawaban menyebutkan perbedaannya, yaitu ketika prototyping fungsi dibagi dengan semua instance (masa depan). Sedangkan mendeklarasikan fungsi di kelas akan membuat salinan untuk setiap instance.
Secara umum tidak ada benar atau salah, ini lebih merupakan masalah selera atau keputusan desain tergantung pada kebutuhan Anda. Namun prototipe adalah teknik yang digunakan untuk mengembangkan dengan cara yang berorientasi objek, karena saya harap Anda akan melihat pada akhir jawaban ini.
Anda menunjukkan dua pola dalam pertanyaan Anda. Saya akan mencoba menjelaskan dua lagi dan mencoba menjelaskan perbedaannya jika relevan. Jangan ragu untuk mengedit / memperluas. Dalam semua contoh ini tentang objek mobil yang memiliki lokasi dan dapat bergerak.
Pola Penghias Objek
Tidak yakin apakah pola ini masih relevan saat ini, tetapi ada. Dan baik untuk mengetahuinya. Anda cukup meneruskan objek dan properti ke fungsi dekorator. Penghias mengembalikan objek dengan properti dan metode.
Kelas Fungsional
Fungsi dalam JavaScript adalah objek khusus. Selain dipanggil, fungsi dapat menyimpan properti seperti objek lainnya.
Dalam hal ini
Car
adalah fungsi ( juga pikirkan objek ) yang dapat dipanggil seperti yang biasa Anda lakukan. Ia memiliki propertimethods
(yang merupakan objek denganmove
fungsi). KetikaCar
dipanggilextend
fungsi dipanggil, yang melakukan beberapa sihir, dan memperluasCar
fungsi (pikirkan objek) dengan metode yang didefinisikan dalammethods
.Contoh ini, meskipun berbeda, paling mendekati contoh pertama dalam pertanyaan.
Kelas Prototypal
Dua pola pertama memungkinkan diskusi tentang menggunakan teknik untuk menentukan metode bersama atau menggunakan metode yang didefinisikan inline di tubuh konstruktor. Dalam kedua kasus setiap instance memiliki fungsinya sendiri
move
.Pola prototypal tidak cocok dengan ujian yang sama, karena pembagian fungsi melalui delegasi prototipe adalah tujuan utama untuk pola prototypal. Seperti yang ditunjukkan orang lain, diharapkan memiliki jejak memori yang lebih baik.
Namun ada satu hal yang menarik untuk diketahui: Setiap
prototype
objek memiliki properti kenyamananconstructor
, yang menunjuk kembali ke fungsi (pikir objek) yang melekat padanya.Mengenai tiga baris terakhir:
Dalam contoh ini
Car
link keprototype
objek, yang menghubungkan melaluiconstructor
untukCar
dirinya sendiri, yaituCar.prototype.constructor
adalahCar
dirinya sendiri. Ini memungkinkan Anda untuk mengetahui fungsi konstruktor mana yang membangun objek tertentu.amy.constructor
Pencarian gagal dan dengan demikian didelegasikan kepadaCar.prototype
, yang memang memiliki properti konstruktor. Begituamy.constructor
jugaCar
.Selanjutnya,
amy
adalahinstanceof
Car
. Theinstanceof
Operator bekerja dengan melihat jika operan kanan ini objek prototipe (Car
) dapat ditemukan di mana saja di prototipe operan kiri ini (amy
) rantai.Beberapa pengembang mungkin bingung pada awalnya. Lihat contoh di bawah ini:
The
instanceof
Operator kembalifalse
, karenaDog
's prototipe tidak dapat ditemukan di mana saja difido
' s rantai prototipe.fido
adalah objek sederhana yang dibuat dengan objek literal, yaitu hanya didelegasikan kepadaObject.prototype
.Pola pseudoklasik
Ini benar-benar hanyalah bentuk lain dari pola prototypal dalam bentuk yang disederhanakan dan lebih akrab untuk dilakukan orang-orang yang memprogram di Jawa misalnya, karena menggunakan
new
konstruktor.Ia melakukan hal yang sama seperti pada pola prototypal, itu hanya sintaksis gula yang melampaui pola prototypal.
Namun, perbedaan utama adalah bahwa ada optimasi diimplementasikan dalam mesin JavaScript yang hanya berlaku ketika menggunakan pola pseudoklasik. Pikirkan pola pseudoklasik versi yang mungkin lebih cepat dari pola prototypal; hubungan objek dalam kedua contoh adalah sama.
Akhirnya, seharusnya tidak terlalu sulit untuk menyadari bagaimana pemrograman berorientasi objek dapat dilakukan. Ada dua bagian.
Satu bagian yang mendefinisikan properti / metode umum dalam prototipe (rantai).
Dan bagian lain di mana Anda meletakkan definisi yang membedakan objek satu sama lain (
loc
variabel dalam contoh).Inilah yang memungkinkan kami untuk menerapkan konsep seperti superclass atau subclass dalam JavaScript.
Jangan ragu untuk menambah atau mengedit. Sekali lagi lengkap saya bisa membuat ini menjadi komunitas wiki.
sumber
Saya percaya bahwa @Matthew Crumley benar. Mereka secara fungsional , jika tidak secara struktural, setara. Jika Anda menggunakan Firebug untuk melihat objek yang dibuat menggunakan
new
, Anda dapat melihat bahwa mereka sama. Namun, preferensi saya adalah sebagai berikut. Saya menduga bahwa sepertinya lebih seperti apa yang saya terbiasa di C # / Java. Yaitu, definisikan kelas, tentukan bidang, konstruktor, dan metode.EDIT Tidak bermaksud menyiratkan bahwa ruang lingkup variabel adalah pribadi, saya hanya mencoba menggambarkan bagaimana saya mendefinisikan kelas saya di javascript. Nama variabel telah diubah untuk mencerminkan ini.
sumber
initialize
danx methods do not refer to the
_instance_var` padaA
instance, tetapi ke properti global. Gunakanthis._instance_var
jika Anda bermaksud menggunakan_instance_var
propertiA
instance.Seperti dibahas dalam jawaban lain, itu benar-benar pertimbangan kinerja karena fungsi dalam prototipe dibagi dengan semua instantiations - daripada fungsi yang dibuat untuk setiap instantiation.
Saya mengumpulkan jsperf untuk menunjukkan ini. Ada perbedaan dramatis dalam waktu yang diperlukan untuk membuat instance kelas, meskipun itu benar-benar hanya relevan jika Anda membuat banyak instance.
http://jsperf.com/functions-in-constructor-vs-prototype
sumber
Pikirkan tentang bahasa yang diketik secara statis, hal-hal pada
prototype
statis dan halthis
-hal terkait misalnya.sumber