Dalam artikel sebelumnya, konsep prototipe diperkenalkan dan hubungan antara tiga teman baik konstruktor, objek prototipe, dan instance dalam JavaScript: masing -masing konstruktor memiliki "wali" - objek prototipe, dan ada juga "posisi" konstruktor di jantung objek prototipe. Keduanya jatuh cinta, tetapi contohnya "diam -diam jatuh cinta" dengan objek prototipe, dan dia juga menjaga posisi objek prototipe di dalam hatinya.
Javascript sendiri bukan bahasa yang berorientasi objek, tetapi bahasa berbasis objek. Bagi mereka yang terbiasa dengan bahasa OO lainnya, itu agak tidak nyaman pada awalnya karena tidak ada konsep "kelas" di sini, atau tidak ada perbedaan antara "kelas" dan "instance", apalagi perbedaan antara "kelas induk" dan "subkelas". Jadi, bagaimana tumpukan objek di JavaScript ini dihubungkan dengan cara ini?
Untungnya, JavaScript memberikan metode implementasi "warisan" di awal desainnya. Sebelum memahami "warisan", kita sekarang akan memahami konsep rantai prototipe.
Rantai prototipe
Kita tahu bahwa prototipe memiliki pointer untuk konstruktor. Bagaimana jika kita membuat objek prototipe subclass sama dengan contoh lain dari superclass baru ()? Pada saat ini, objek prototipe subclass berisi pointer ke prototipe superclass, dan prototipe superclass juga berisi pointer ke konstruktor superclass. . . Dengan cara ini, rantai prototipe terbentuk.
Kode spesifiknya adalah sebagai berikut:
function superclass () {this.name = "women"} superclass.prototype.saywhat = function () {return this.name + ": i`mA girl!"; } function subclass () {this.subname = "Sister Anda"; } Subclass.prototype = new superclass (); Subclass.prototype.subsaywhat = function () {return this.subname + ": i`ma cantik gadis"; } var sub = subclass baru (); Console.log (sub.saywhat ()); // Wanita: I`Ma Girl!Gunakan rantai prototipe untuk mencapai warisan
Dari kode di atas, kita dapat melihat bahwa subclass mewarisi properti dan metode superclass. Implementasi yang diwariskan ini adalah dengan menetapkan instance superclass ke objek prototipe subclass. Dengan cara ini, objek prototipe subclass ditimpa oleh instance superclass, memiliki semua sifat dan metode, dan juga memiliki pointer ke objek prototipe superclass.
Ada beberapa hal yang perlu diperhatikan saat menerapkan warisan menggunakan rantai prototipe:
Perhatikan perubahan konstruktor setelah warisan. Di sini konstruktor sub poin ke superclass karena prototipe titik subkelas ke superclass. Saat memahami rantai prototipe, jangan abaikan objek objek default di akhir, itulah sebabnya kita dapat menggunakan metode bawaan seperti tostring di semua objek.
Saat menerapkan warisan melalui rantai prototipe, Anda tidak dapat menggunakan definisi literal dari metode prototipe, karena ini akan menulis ulang objek prototipe (juga diperkenalkan dalam artikel sebelumnya):
function superclass () {this.name = "women"} superclass.prototype.saywhat = function () {return this.name + ": i`mA girl!"; } function subclass () {this.subname = "Sister Anda"; } Subclass.prototype = new superclass (); Subclass.prototype = {// Objek prototipe ditimpa di sini karena atribut dan metode superclass tidak dapat diwarisi subsay apa: function () {return this.subname + ": i`mA cantik gadis"; }} var Sub = subclass baru (); console.log (sub.saywhat ()); // typeError: undefined bukan fungsiMasalah dengan berbagi instance. Saat menjelaskan prototipe dan konstruktor sebelumnya, kami pernah memperkenalkan bahwa prototipe yang mengandung atribut jenis referensi akan dibagikan oleh semua contoh. Demikian pula, sifat -sifat jenis referensi dalam prototipe "kelas induk" juga akan dibagikan dalam prototipe. Ketika kami memodifikasi atribut tipe referensi dari "kelas induk" melalui pewarisan prototipe, semua contoh lain yang diwarisi dari prototipe akan terpengaruh. Ini tidak hanya membuang -buang sumber daya, tetapi juga sebuah fenomena yang tidak ingin kita lihat:
function superclass () {this.name = "women"; this.bra = ["a", "b"]; } function subclass () {this.subname = "Sister Anda"; } Subclass.prototype = new superclass (); var sub1 = subclass baru (); sub1.name = "man"; sub1.bra.push ("c"); console.log (sub1.name); // man console.log (sub1.bra); // ["a", "b", "c"] var sub2 = subclass baru (); console.log (sub1.name); // woman console.log (sub2.bra); // ["a", "b", "c"]Catatan: Tambahkan elemen ke array di sini, semua contoh yang diwarisi dari superclass akan terpengaruh, tetapi jika Anda memodifikasi atribut nama, itu tidak akan mempengaruhi contoh lain, karena array adalah jenis referensi dan nama adalah tipe primitif.
Bagaimana cara menyelesaikan masalah berbagi instance? Mari kita terus melihat ke bawah ...
Warisan klasik (mencuri konstruktor)
Karena kami telah memperkenalkan bahwa kami jarang menggunakan prototipe untuk mendefinisikan objek saja, dalam pengembangan yang sebenarnya, kami jarang menggunakan rantai prototipe saja. Untuk memecahkan masalah berbagi jenis referensi, pengembang JavaScript telah memperkenalkan pola warisan klasik (beberapa orang menyebut warisan konstruktor pinjaman). Implementasinya sangat mudah untuk memanggil konstruktor supertype dalam konstruktor subtipe. Kita perlu menggunakan fungsi panggilan () atau terapkan () yang disediakan oleh JavaScript, mari kita lihat contohnya:
function superclass () {this.name = "women"; this.bra = ["a", "b"];} function subclass () {this.subname = "saudari Anda"; // Tetapkan ruang lingkup superclass ke konstruktor saat ini untuk mengimplementasikan pewarisan superclass.call (ini);} var sub1 = subklass baru (); sub1.bra.push ("c"); console.log (sub1.bra); // ["a", "b", "c"] var sub2 = Subclass (); console.log (sub2.bra); // ["a", "b"]Superclass.call (ini); Kalimat ini berarti bahwa pekerjaan inisialisasi konstruktor superclass disebut dalam lingkungan instance (konteks) subclass, sehingga setiap contoh akan memiliki salinan atribut BRA sendiri, yang tidak akan berpengaruh satu sama lain.
Namun, metode implementasi ini masih belum sempurna. Karena konstruktor diperkenalkan, kami juga menghadapi masalah dengan konstruktor yang disebutkan dalam artikel sebelumnya: Jika ada definisi metode dalam konstruktor, maka ada referensi fungsi terpisah untuk tidak ada contoh. Tujuan kami adalah untuk berbagi metode ini, dan metode yang kami tentukan dalam prototipe supertype tidak dapat dipanggil dalam contoh subtipe:
function superclass () {this.name = "women"; this.bra = ["a", "b"]; } Superclass.prototype.saywhat = function () {console.log ("hello"); } function subclass () {this.subname = "Sister Anda"; Superclass.call (ini); } var sub1 = subkelas baru (); console.log (sub1.saywhat ()); // typeerror: tidak terdefinisi bukan fungsiJika Anda telah membaca artikel sebelumnya tentang objek dan konstruktor prototipe, Anda harus sudah tahu jawaban untuk menyelesaikan masalah ini, yaitu, ikuti rutin dari artikel sebelumnya dan gunakan "Punch Combination"!
Warisan Kombinasi
Kombinasi warisan adalah cara untuk menggabungkan keunggulan rantai prototipe dan konstruktor, dan untuk menggabungkannya untuk mencapai warisan. Sederhananya, ini adalah menggunakan rantai prototipe untuk mewarisi atribut dan metode, dan menggunakan konstruktor yang dipinjam untuk menerapkan pewarisan atribut instance. Ini tidak hanya memecahkan masalah berbagi atribut instance, tetapi juga memungkinkan atribut dan metode tipe super untuk diwariskan:
function superclass () {this.name = "women"; this.bra = ["a", "b"]; } Superclass.prototype.saywhat = function () {console.log ("hello"); } function subclass () {this.subname = "Sister Anda"; Superclass.call (ini); // panggilan kedua ke superclass} subclass.prototype = new superclass (); // Panggilan pertama ke superclass var sub1 = subclass baru (); console.log (sub1.saywhat ()); //HaloMetode warisan kombinasi juga merupakan cara yang paling umum digunakan untuk mengimplementasikan warisan dalam pengembangan aktual. Pada titik ini, itu dapat memenuhi kebutuhan pengembangan Anda yang sebenarnya, tetapi pengejaran kesempurnaan orang tidak ada habisnya, jadi pasti akan ada seseorang "menemukan" tentang pola ini: pola Anda telah disebut konstruktor tipe super dua kali! Dua kali. . . Apakah Anda berhasil? Apakah amplifikasi 100 kali lipat dari kehilangan kinerja ini?
Sanggahan yang paling kuat adalah menghasilkan solusi, tetapi untungnya pengembang telah menemukan solusi terbaik untuk masalah ini:
Warisan kombinasi parasit
Sebelum memperkenalkan metode warisan ini, pertama -tama kita memahami konsep konstruktor parasit. Konstruktor parasit mirip dengan pola pabrik yang disebutkan di atas. Idenya adalah untuk mendefinisikan fungsi umum. Fungsi ini secara khusus digunakan untuk menangani pembuatan suatu objek. Setelah kreasi selesai, ia mengembalikan objek ini. Fungsi ini sangat mirip dengan konstruktor, tetapi konstruktor tidak mengembalikan nilai:
fungsi gf (nama, bra) {var obj = objek baru (); obj.name = nama; obj.bra = bra; obj.saywhat = function () {console.log (this.name); } return obj;} var gf1 = GF baru ("bingbing", "c ++"); console.log (gf1.saywhat ()); // bingbingImplementasi pewarisan parasit mirip dengan konstruktor parasit. Ini menciptakan fungsi "pabrik" yang tidak bergantung pada tipe tertentu, secara khusus berurusan dengan proses warisan objek, dan kemudian mengembalikan instance objek yang diwariskan. Untungnya, ini tidak mengharuskan kita untuk menerapkannya sendiri. Dao Ge (Douglas) telah lama memberi kami metode implementasi:
objek fungsi (obj) {function f () {} f.prototype = obj; return new f ();} var superclass = {name: "bingbing", bra: "c ++"} var subclass = objek (superclass); console.log (subclass.name); // bingbingKonstruktor sederhana disediakan dalam fungsi publik, dan kemudian instance objek yang dilewati ditetapkan untuk objek prototipe konstruktor, dan akhirnya mengembalikan contoh konstruktor sangat sederhana, tetapi kemanjurannya sangat bagus, bukan? Metode ini kemudian disebut "prototipe warisan", dan pewarisan parasit dicapai berdasarkan prototipe dengan meningkatkan sifat khusus objek:
fungsi buildobj (obj) {var o = objek (obj); o.saywhat = function () {console.log ("hello"); } return o;} var superclass = {name: "bingbing", bra: "c ++"} var gf = buildobj (superclass); gf.saywhat (); // haloWarisan parasit juga menghadapi masalah fungsi penggunaan kembali dalam prototipe, sehingga orang mulai merakit blok bangunan lagi, dan pewarisan kombinasi parasit lahir, dengan tujuan memecahkan masalah memanggil konstruktor tipe induk ketika menentukan prototipe subtipe, dan pada saat yang sama, untuk memaksimalkan penggunaan kembali fungsi. Berdasarkan metode implementasi dasar di atas adalah sebagai berikut:
// Parameternya adalah dua konstruktor fungsi warisan (sub, sup) {// mengimplementasikan instance pewarisan dan mendapatkan salinan supertype var proto = objek (sup.prototype); // Respecify atribut konstruktor dari proto proto Proto.constructor = sub; // Tetapkan objek yang dibuat ke prototipe subtipe sub.prototype = proto;} function superclass () {this.name = "women"; this.bra = ["a", "b"];} superclass.prototype.saywhat = function () {console.log ("hello");} function subclass () {this.name = "women"; this.bra = ["a", "b"];} superclass.prototype.saywhat = function () {console.log ("hello");} function subclass () {this.subname = "saudari Anda"; Superclass.call (this);} inheritoBj (subclass, superclass); var sub1 = subclass baru (); console.log (sub1.saywhat ()); //HaloImplementasi ini menghindari dua panggilan ke supertype, dan juga menyimpan sifat yang tidak perlu pada subclass.prototype, dan juga mempertahankan rantai prototipe. Pada titik ini, perjalanan warisan benar -benar berakhir, dan implementasi ini juga telah menjadi metode implementasi warisan yang paling ideal! Kontroversi orang atas warisan JavaScript masih berlanjut. Beberapa advokat oo, dan beberapa menentang melakukan upaya yang tidak perlu dalam JavaScript untuk mewujudkan karakteristik OO. Bagaimana jika itu, setidaknya saya memiliki pemahaman yang lebih dalam!