Apa bedanya
var A = function () {
this.x = function () {
//do something
};
};
dan
var A = function () { };
A.prototype.x = function () {
//do something
};
a1.x !== a2.x
:; pada prototipe:a1.x === a2.x
Apa bedanya
var A = function () {
this.x = function () {
//do something
};
};
dan
var A = function () { };
A.prototype.x = function () {
//do something
};
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:
var A = function () {
this.x = function () {
//do something
};
};
Dalam hal ini, variabel A
diberi nilai yang merupakan referensi ke suatu fungsi. Ketika fungsi itu disebut menggunakan A()
, fungsi ini tidak diatur oleh panggilan sehingga default ke objek global dan ekspresi this.x
efektif window.x
. Hasilnya adalah referensi ke ekspresi fungsi di sisi kanan ditugaskan window.x
.
Dalam kasus:
var A = function () { };
A.prototype.x = function () {
//do something
};
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):
var A = new function () {
this.x = function () {
//do something
};
};
Dalam contoh ini, new
operator telah ditambahkan sebelum ekspresi fungsi sehingga fungsi tersebut disebut sebagai konstruktor. Ketika dipanggil dengan new
, 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 untuk return this;
pernyataan yang terpisah .
Untuk memeriksa bahwa A memiliki properti x :
console.log(A.x) // function () {
// //do something
// };
Ini adalah penggunaan baru yang tidak biasa karena satu-satunya cara untuk merujuk konstruktor adalah melalui A.constructor . Akan lebih umum dilakukan:
var A = function () {
this.x = function () {
//do something
};
};
var a = new A();
Cara lain untuk mencapai hasil yang serupa adalah dengan menggunakan ekspresi fungsi yang langsung dipanggil:
var A = (function () {
this.x = function () {
//do something
};
}());
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 dan this.x
efektif window.x
. Karena fungsi tidak mengembalikan apa pun, A
akan memiliki nilai undefined
.
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:
var A = function () {
this.objectsOwnProperties = "are serialized";
};
A.prototype.prototypeProperties = "are NOT serialized";
var instance = new A();
console.log(instance.prototypeProperties); // "are NOT serialized"
console.log(JSON.stringify(instance));
// {"objectsOwnProperties":"are serialized"}
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.
null
), tetapi ini sangat berbeda dari prototype
properti - yang ada di fungsi dan yang prototipe dari semua instance diatur ketika mereka dibangun dengan new
. 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:
// x is a method assigned to the object using "this"
var A = function () {
this.x = function () { alert('A'); };
};
A.prototype.updateX = function( value ) {
this.x = function() { alert( value ); }
};
var a1 = new A();
var a2 = new A();
a1.x(); // Displays 'A'
a2.x(); // Also displays 'A'
a1.updateX('Z');
a1.x(); // Displays 'Z'
a2.x(); // Still displays 'A'
// Here x is a method assigned to the object using "prototype"
var B = function () { };
B.prototype.x = function () { alert('B'); };
B.prototype.updateX = function( value ) {
B.prototype.x = function() { alert( value ); }
}
var b1 = new B();
var b2 = new B();
b1.x(); // Displays 'B'
b2.x(); // Also displays 'B'
b1.updateX('Y');
b1.x(); // Displays 'Y'
b2.x(); // Also displays 'Y' because by using prototype we have changed it for all instances
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.
this
objek, yang merupakan pemilik metode. yaitu metode tidak memiliki objek yang merupakan pemiliknya. Dalam hal ini ada this
objek, seperti yang ditunjukkan di kelas A dalam contoh.
Ambil 2 contoh ini:
var A = function() { this.hey = function() { alert('from A') } };
vs.
var A = function() {}
A.prototype.hey = function() { alert('from prototype') };
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 mengetik anyObject.__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 menggunakannya var 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 ke null
.
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:
var A = [];
A.prototype // undefined
A = function() {}
A.prototype // {} // got created when function() {} was defined
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 ke null
, semoga beruntung, JavaScript menyadari itu dan akan mengembalikan Anda undefined
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
:
var a1 = new 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 fungsi A()
melakukan sesuatu TAMBAHAN di latar belakang. Kata new
kunci membuat objek baru yang sekarang referensi a1
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 oleh new
operator adalah menetapkan __proto__
properti itu untuk menunjuk ke prototype
properti fungsi . Baca lagi. Ini pada dasarnya ini:
a1.__proto__ = A.prototype;
Kami mengatakan bahwa A.prototype
tidak lebih dari objek kosong (kecuali kami mengubahnya ke sesuatu yang lain sebelum mendefinisikan a1
). Jadi sekarang pada dasarnya a1.__proto__
menunjuk ke hal yang sama A.prototype
menunjuk ke, yaitu objek kosong itu. Keduanya menunjuk ke objek yang sama yang dibuat ketika baris ini terjadi:
A = function() {} // JS: cool. let's also create A.prototype pointing to empty {}
Sekarang, ada hal lain yang terjadi ketika var a1 = new A()
pernyataan diproses. Pada dasarnya A()
dieksekusi dan jika A adalah sesuatu seperti ini:
var A = function() { this.hey = function() { alert('from A') } };
Semua hal di dalam function() { }
akan dieksekusi. Ketika Anda mencapai this.hey..
garis, this
diubah ke a1
dan Anda mendapatkan ini:
a1.hey = function() { alert('from A') }
Saya tidak akan membahas mengapa this
perubahan a1
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 dengan A.prototype
menunjuk ke (objek kosong lain {})
Fungsi A()
ini dieksekusi dengan this
set ke objek kosong baru yang dibuat pada langkah 1 (baca jawaban yang saya rujuk di atas tentang mengapa this
perubahan a1
)
Sekarang, mari kita coba membuat objek lain:
var a2 = new A();
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 sama A.prototype
dan yang paling penting, langkah 3: fungsi A()
LAGI dieksekusi, yang berarti bahwa a2
akan mendapatkan hey
properti yang mengandung fungsi. a1
dan a2
memiliki dua properti SEPARATE bernama hey
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 mengambil yoMan
properti pada a1
(yang tidak ada), __proto__
propertinya akan dikonsultasikan, yang jika itu adalah objek (dan sebagian besar kasusnya adalah), ia akan memeriksa apakah itu berisi yoMan
, 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:
var A = function() {}
A.prototype.hey = function() { alert('from prototype') };
Keren! Sekarang, ketika Anda membuat a1
, itu lagi melewati semua 3 langkah di atas, dan pada langkah 3, itu tidak melakukan apa-apa, karena function A()
tidak ada yang dieksekusi. Dan jika kita melakukannya:
a1.hey
Ini akan melihat yang a1
tidak mengandung hey
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
dan a2
memiliki hey
properti terpisah , sekarang NONE dari mereka memilikinya. Yang, kurasa, kau sudah tahu sendiri sekarang. Itu hal yang baik ... jika Anda mengerti __proto__
dan Function.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 dengan Functional.prototype
properti sebagai dua hal yang berbeda.
__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:
var A = function () {
var private_var = ...;
this.x = function () {
return private_var;
};
this.setX = function (new_x) {
private_var = new_x;
};
};
Karena aturan pelingkupan javascript, private_var tersedia untuk fungsi yang ditetapkan untuk this.x, tetapi tidak di luar objek.
Contoh pertama mengubah antarmuka untuk objek itu saja. Contoh kedua mengubah antarmuka untuk semua objek dari kelas itu.
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-alih prototype
adalah ketika menimpa metode, konstruktor dari kelas dasar masih akan merujuk pada metode yang diganti. Pertimbangkan ini:
BaseClass = function() {
var text = null;
this.setText = function(value) {
text = value + " BaseClass!";
};
this.getText = function() {
return text;
};
this.setText("Hello"); // This always calls BaseClass.setText()
};
SubClass = function() {
// setText is not overridden yet,
// so the constructor calls the superclass' method
BaseClass.call(this);
// Keeping a reference to the superclass' method
var super_setText = this.setText;
// Overriding
this.setText = function(value) {
super_setText.call(this, "SubClass says: " + value);
};
};
SubClass.prototype = new BaseClass();
var subClass = new SubClass();
console.log(subClass.getText()); // Hello BaseClass!
subClass.setText("Hello"); // setText is already overridden
console.log(subClass.getText()); // SubClass says: Hello BaseClass!
melawan:
BaseClass = function() {
this.setText("Hello"); // This calls the overridden method
};
BaseClass.prototype.setText = function(value) {
this.text = value + " BaseClass!";
};
BaseClass.prototype.getText = function() {
return this.text;
};
SubClass = function() {
// setText is already overridden, so this works as expected
BaseClass.call(this);
};
SubClass.prototype = new BaseClass();
SubClass.prototype.setText = function(value) {
BaseClass.prototype.setText.call(this, "SubClass says: " + value);
};
var subClass = new SubClass();
console.log(subClass.getText()); // SubClass says: Hello BaseClass!
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.
var A = function (param1) {
var privateVar = null; // Private variable
// Calling this.setPrivateVar(param1) here would be an error
this.setPrivateVar = function (value) {
privateVar = value;
console.log("setPrivateVar value set to: " + value);
// param1 is still here, possible memory leak
console.log("setPrivateVar has param1: " + param1);
};
// The constructor logic starts here possibly after
// many lines of code that define methods
this.setPrivateVar(param1); // This is valid
};
var a = new A(0);
// setPrivateVar value set to: 0
// setPrivateVar has param1: 0
a.setPrivateVar(1);
//setPrivateVar value set to: 1
//setPrivateVar has param1: 0
melawan:
var A = function (param1) {
this.setPublicVar(param1); // This is valid
};
A.prototype.setPublicVar = function (value) {
this.publicVar = value; // No private variable
};
var a = new A(0);
a.setPublicVar(1);
console.log(a.publicVar); // 1
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 menggunakan new
.
Dalam contoh pertama Anda, Anda menambahkan properti x
ke setiap instance yang dibuat dengan A
fungsi.
var A = function () {
this.x = function () {
//do something
};
};
var a = new A(); // constructor function gets executed
// newly created object gets an 'x' property
// which is a function
a.x(); // and can be called like this
Dalam contoh kedua Anda menambahkan properti ke objek prototipe yang dibuat semua A
titik dengan menunjuk.
var A = function () { };
A.prototype.x = function () {
//do something
};
var a = new A(); // constructor function gets executed
// which does nothing in this example
a.x(); // you are trying to access the 'x' property of an instance of 'A'
// which does not exist
// so JavaScript looks for that property in the prototype object
// that was defined using the 'prototype' property of the constructor
Sebagai kesimpulan, dalam contoh pertama salinan fungsi ditugaskan untuk setiap contoh . Dalam contoh kedua, satu salinan fungsi dibagikan oleh semua instance .
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:
var AdultPerson = function() {
var age;
this.setAge = function(val) {
// some housekeeping
age = val >= 18 && val;
};
this.getAge = function() {
return age;
};
this.isValid = function() {
return !!age;
};
};
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.
AdultPerson.prototype.getRights = function() {
// Should be valid
return this.isValid() && ['Booze', 'Drive'];
};
Mari kita lihat implementasinya sekarang.
var p1 = new AdultPerson;
p1.setAge(12); // ( age = false )
console.log(p1.getRights()); // false ( Kid alert! )
p1.setAge(19); // ( age = 19 )
console.log(p1.getRights()); // ['Booze', 'Drive'] ( Welcome AdultPerson )
var p2 = new AdultPerson;
p2.setAge(45);
console.log(p2.getRights()); // The same getRights() method, *** not a new copy of it ***
Semoga ini membantu.
Prototipe adalah templat kelas; yang berlaku untuk semua contoh masa depan itu. Padahal ini adalah contoh khusus dari objek.
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. Memakai print
prototipe membutuhkan sekitar 1/2 selama.
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.
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.
var carlike = function(obj, loc) {
obj.loc = loc;
obj.move = function() {
obj.loc++;
};
return obj;
};
var amy = carlike({}, 1);
amy.move();
var ben = carlike({}, 9);
ben.move();
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 properti methods
(yang merupakan objek dengan move
fungsi). Ketika Car
dipanggil extend
fungsi dipanggil, yang melakukan beberapa sihir, dan memperluas Car
fungsi (pikirkan objek) dengan metode yang didefinisikan dalam methods
.
Contoh ini, meskipun berbeda, paling mendekati contoh pertama dalam pertanyaan.
var Car = function(loc) {
var obj = {loc: loc};
extend(obj, Car.methods);
return obj;
};
Car.methods = {
move : function() {
this.loc++;
}
};
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();
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 kenyamanan constructor
, yang menunjuk kembali ke fungsi (pikir objek) yang melekat padanya.
Mengenai tiga baris terakhir:
Dalam contoh ini Car
link ke prototype
objek, yang menghubungkan melalui constructor
untuk Car
dirinya sendiri, yaitu Car.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 kepada Car.prototype
, yang memang memiliki properti konstruktor. Begitu amy.constructor
juga Car
.
Selanjutnya, amy
adalah instanceof
Car
. The instanceof
Operator bekerja dengan melihat jika operan kanan ini objek prototipe ( Car
) dapat ditemukan di mana saja di prototipe operan kiri ini ( amy
) rantai.
var Car = function(loc) {
var obj = Object.create(Car.prototype);
obj.loc = loc;
return obj;
};
Car.prototype.move = function() {
this.loc++;
};
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();
console.log(Car.prototype.constructor);
console.log(amy.constructor);
console.log(amy instanceof Car);
Beberapa pengembang mungkin bingung pada awalnya. Lihat contoh di bawah ini:
var Dog = function() {
return {legs: 4, bark: alert};
};
var fido = Dog();
console.log(fido instanceof Dog);
The instanceof
Operator kembali false
, karena Dog
's prototipe tidak dapat ditemukan di mana saja di fido
' s rantai prototipe. fido
adalah objek sederhana yang dibuat dengan objek literal, yaitu hanya didelegasikan kepadaObject.prototype
.
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.
var Car = function(loc) {
this.loc = loc;
};
Car.prototype.move = function() {
this.loc++;
};
var amy = new Car(1);
amy.move();
var ben = new Car(9);
ben.move();
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.
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.
var A = function() {};
A.prototype = {
_instance_var: 0,
initialize: function(v) { this._instance_var = v; },
x: function() { alert(this._instance_var); }
};
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.
initialize
dan x methods do not refer to the
_instance_var` pada A
instance, tetapi ke properti global. Gunakan this._instance_var
jika Anda bermaksud menggunakan _instance_var
properti A
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.