Apa prototipe
Jenis fungsi memiliki prototipe properti, yang diterjemahkan langsung ke dalam prototipe. Properti ini adalah pointer, menunjuk ke suatu objek, yang berisi beberapa properti dan metode, yang akan dibagikan oleh semua contoh (objek) yang dihasilkan oleh fungsi saat ini.
Berdasarkan apa yang dikatakan sebelumnya, Anda bisa mendapatkan kode berikut:
function person () {...} person.prototype = {country: 'cina', sayname: function () {...}}Pertama, instance orang dari tipe fungsi dibuat, dan kemudian prototipe metode orang tersebut adalah objek, dan deklarasi menunjuk ke suatu objek. Properti dan metode dalam objek ini akan dibagikan oleh instance yang dihasilkan oleh fungsi orang saat ini. Artinya:
orang1 = orang baru (); orang2 = orang baru ();
Person1 dan Person2 keduanya dihasilkan lagi melalui instance jenis fungsi orang. Keduanya memiliki negara properti umum dan metode Sayname, karena mereka semua memiliki pointer (__proto__), menunjuk langsung ke objek yang ditunjukkan oleh orang. Prototipe. Namun, harap dicatat bahwa penunjuk __proto__ bukan standar. Ini hanya ditentukan oleh browser seperti Chrome dan Firefox. Bahkan, properti ini tidak akan digunakan, tetapi hanya digunakan sebagai pemahaman prototipe:
Mengenai penggunaan prototipe dan metode lainnya, kami akan membicarakannya secara lebih spesifik nanti.
Buat pola objek
Selanjutnya, mari kita lihat metode dan pola umum untuk membuat objek, serta kelebihan dan kekurangannya.
1. Model pabrik
Sama seperti pabrik, proses membuat objek konkret diabstraksikan, dan fungsi digunakan untuk merangkum detail membuat objek dengan antarmuka tertentu. Dengan menggunakan fungsi alih -alih pekerjaan pengulangan parsial, kode ini adalah sebagai berikut:
function createPerson (nama, usia, pekerjaan) {var o = objek baru (); o.name = nama; o.age = usia; o.job = pekerjaan; o.sayname = function () {alert (this.name); }; return o;} var person1 = createPerson ("Jiangshui", "22", "Engineer");Ini menciptakan seseorang, dan pola pabrik memecahkan masalah penciptaan berulang dari beberapa objek serupa, tetapi tidak menyelesaikan masalah pengenalan objek. Hanya saja suatu objek hanya dibuat, dan tidak peduli apakah objek ini dibuat dari templat manusia atau templat hewan, tidak mungkin untuk membedakan jenis objek ini.
2. Mode Konstruktor
Buat konstruktor khusus untuk mendefinisikan properti dan metode jenis objek khusus.
Function Person (Name, Umur, Job) {this.name = name; this.age = usia; this.job = jpb; this.sayname = function () {alert (this.name); };}; var person1 = orang baru (...);3. Perbedaan antara mode konstruktor dan mode pabrik:
Orang adalah objek tipe fungsi. Setelah baru, suatu objek akan terus dihasilkan. Namun, karena objek yang baru dihasilkan ini dilewatkan dalam fungsi dan ditugaskan ke pointer ini, konten yang dilewati menjadi properti atau metode objek yang baru dihasilkan.
Kebiasaan konstruktor default dikapitalisasi dalam huruf pertama. Eksekusi kode di atas melewati langkah -langkah berikut:
Dalam hal yang dihasilkan dengan cara ini, mereka semua berisi atribut konstruktor secara default menunjuk ke fungsi konstruktor, misalnya:
peringatan (person1.constructor == orang);
Oleh karena itu, menggunakan pola konstruktor, ada perbedaan jenis, dan instance dapat diidentifikasi sebagai tipe tertentu.
Selain itu, konstruktor adalah fungsi biasa. Karena Anda ingin umpan balik untuk mendapatkan objek baru, Anda menggunakan yang baru untuk menyebutnya. Jika tidak, menjalankannya secara langsung seperti fungsi normal. Misalnya, jika Anda mengeksekusi orang.
Mode konstruktor juga cacat. Metode dalam mode konstruktor diciptakan kembali pada setiap instance, jadi fungsi dengan nama yang sama pada contoh yang berbeda tidak sama. Misalnya:
person1.sayname == orang2.sayname; //PALSU
Dengan kata lain, setiap contoh objek, atribut dan metode yang dihasilkan oleh konstruktor unik dan disalin. Atribut adalah unik, karena ini adalah perbedaan antara objek, tetapi banyak metode memiliki fungsi dan kode yang sama. Jika Anda menyalinnya berulang kali berkali -kali, Anda jelas akan membuang sumber daya.
Jadi kita dapat meletakkan fungsi di luar dan kemudian menunjuk ke fungsi dengan pointer di konstruktor. Dalam contoh yang dihasilkan, metode ini menyimpan pointer ke fungsi tertentu, yang berarti fungsi bersama:
function person (name, use) {this.name = name; this.age = usia; this.sayname = SayName;} function Saysname () {waspada (this.name);}Namun, dengan cara ini, fungsi ini menjadi fungsi global, dan tidak terlalu berkorelasi dengan konstruktor orang dan tidak memiliki enkapsulasi.
Selanjutnya, silakan datang ke mode prototipe.
Mode prototipe
Bagian dari dasar -dasar tentang prototipe telah diperkenalkan sebelumnya. Sederhananya, setiap fungsi memiliki atribut prototipe, menunjuk ke objek (objek prototipe), dan beberapa properti atau metode dapat ditempatkan di objek ini. Kemudian instance yang dihasilkan oleh fungsi ini akan memiliki atribut yang tidak teratur (__proto__) yang menunjuk ke prototipe.
Dari sudut pandang ini, Anda harus dapat memahami bahwa sifat dan metode yang dihasilkan oleh prototipe dibagikan oleh semua contoh.
Ini hanya memecahkan masalah berbagi fungsi dalam mode konstruktor di atas dan dalam contoh. Misalnya, kode berikut:
function person () {....} person.prototype.name = "jiangshui"; person.prototype.sayname = function () {waspada (this.name);}; var person1 = orang baru (); person1.sayname (); // Jiangshuiatau
Person.prototype = {constructor: person, name: "jiangshui", sayname: function () {waspada (this.name); }};Metode kedua mencakup seluruh objek prototipe, jadi Anda perlu menentukan secara manual properti konstruktor, menunjuk ke fungsi konstruktor, jika tidak ia akan menunjuk ke objek.
Mari kita selesaikan hubungan mereka:
Gunakan isPrototypeOf () untuk menentukan hubungan antara objek. Misalnya:
Orang.prototype.isprototypeOf (Person1);
Ketika kode membaca properti tertentu dari suatu objek, pencarian akan dilakukan. Mulailah dengan objek saat ini, dan jika tidak, cari objek prototipe yang ditunjukkan oleh pointer, tanpa mencari konstruktor. Contoh objek dapat diakses tetapi tidak dapat mengganti nilai objek prototipe. Jika atribut dengan nama yang sama dengan objek prototipe diatur dalam instance, proses pencarian berakhir pada instance tanpa mengakses objek prototipe, sehingga tujuan timpa tercapai. Oleh karena itu, bahkan jika properti ini diatur ke NULL, itu berarti bahwa properti sudah ada dalam contoh, dan properti tidak akan dibatalkan, sehingga properti prototipe yang sesuai dapat diakses.
Oleh karena itu, Anda perlu menggunakan operator hapus untuk menghapus atribut instance sepenuhnya sehingga prototipe dapat ditinjau kembali.
Prototipe adalah dinamis, dan setiap modifikasi yang dibuat untuk objek prototipe dapat segera tercermin dari instance. Alasannya adalah hubungan tautan longgar antara instance dan prototipe. Setiap kali metode properti instance dipanggil, kueri akan dilakukan. Jika prototipe berubah, hasil kueri juga akan berubah.
Setelah memahami prototipe, kami juga dapat menambahkan metode atau atribut baru ke objek asli. Jenis referensi asli seperti objek, array, string, dll. Mirip dengan konstruktor di atas. Kita dapat menggunakan prototipe untuk memperluas metode mereka. Misalnya:
String.prototype.startswith = function (teks) {return this.indexof (teks) == 0;}; var msg = "hello world"; msg.startswith ("hello");Kode ini menambahkan metode StartSwith ke string tipe referensi asli, yaitu untuk melewati parameter untuk melihat apakah string yang akan diuji dimulai dengan parameter. Karena sifat dinamis dari prototipe, semua variabel tipe string mendapatkan metode ini dengan mengeksekusi.
Namun, metode ini tidak disarankan. Jika Anda menggunakan terlalu banyak dan terlalu banyak kode, itu akan menyebabkan kesulitan pemeliharaan, kebingungan dalam kode, dll. Secara umum, jenis referensi asli akan diwarisi terlebih dahulu, dan kemudian dibuat pada jenis yang baru disesuaikan. Mengenai warisan, kami akan merangkumnya nanti.
Pola prototipe juga tidak mahakuasa. Semua atribut dan metode dalam prototipe dibagikan oleh semua contoh, sehingga sangat cocok untuk fungsi dan fungsi lainnya, tetapi untuk atribut yang mengandung jenis referensi, beberapa konflik akan muncul. Misalnya:
function person () {} person.prototype = {konstruktor: orang, teman: ["greg", "jack"]}; var person1 = orang baru (); var person2 = orang baru (); orang1.friends.push ("tom"); console.log (person2.friends);Anda akan melihat di konsol bahwa ada tom tambahan untuk teman2 teman, yang bukan yang saya inginkan, tetapi ketika mendefinisikan temannya kepada orang1, itu memengaruhi orang contoh2.
Jadi kita perlu menggunakannya dalam kombinasi dengan pola prototipe dan pola konstruktor.
Gunakan mode konstruktor dan mode prototipe dalam kombinasi
Ini adalah pola yang paling umum digunakan. Konstruktor digunakan untuk mendefinisikan properti instan dan menyesuaikan dengan melewati parameter; Prototipe digunakan untuk mendefinisikan metode atau atribut yang memerlukan berbagi di antara semua contoh. Dengan cara ini, kustomisasi tercapai, berbagi dipastikan, dan masalah dihindari.
Function Person (Name, Umur, Job) {this.name = name; this.age = usia; this.job = pekerjaan; this.friends = ["greg", "jack"];} person.prototype = {constructor: person, sayname: function () {waspada (this.name); }}; var Jiangshui = orang baru ("Jiangshui", "22", "Engineer");Contoh aplikasi praktis
Oke, di sini Anda mungkin mengerti apa prototipe itu dan bagaimana membuat objek, tetapi apa penggunaannya? Memang, pekerjaan saya sebelumnya hanya untuk menulis beberapa kode menggunakan jQuery, dan saya tidak bisa menggunakan enkapsulasi dan kemudian menghasilkan objek untuk mengimplementasikan fungsi, dll. Jadi, apa penggunaannya?
Metode pengembangan ini terutama digunakan untuk pengembangan modular dan perakitan. Misalnya, fungsi pop-up yang sering Anda gunakan, tentu saja Anda dapat menempelkan dan menyalin kode pop-up setiap kali, dan kemudian memodifikasinya dan menggunakannya dalam proyek. Pilihan yang lebih baik adalah merangkum kode fungsi pop-up secara abstrak ke dalam komponen seperti itu, sehingga ketika Anda perlu menggunakan pop-up, Anda hanya perlu meneruskan parameter untuk menghasilkan instance pop-up, dan Anda dapat menyebutnya.
Objek prototipe dan rantai prototipe
Dalam JavaScript, semuanya adalah objek, tetapi ada juga perbedaan objek. Ini dapat dibagi secara kasar menjadi dua kategori, yaitu: objek biasa (objek) dan objek fungsi (fungsi).
Secara umum, objek yang dihasilkan melalui fungsi baru adalah objek fungsi, dan objek lain adalah objek biasa.
Berikan contoh:
function f1 () {// tODO} var f2 = function () {// TODO}; var f3 = function baru ('x', 'console.log (x)'); var o1 = {}; var o2 = objek baru (); var o3 = f1 baru (); console.log (typeof f1, // function typeof f2, // function typeof f3, // function typeof o1, // objek typeof o2, // objek typeof o3 // objek); >> fungsi objek objek objek objek objek objek fungsi fungsi objek objekF1 termasuk dalam deklarasi suatu fungsi. Cara paling umum untuk mendefinisikan fungsi adalah bahwa F2 sebenarnya adalah fungsi anonim. Tetapkan fungsi anonim ini ke F2, yang termasuk dalam ekspresi fungsi. F3 tidak umum, tetapi juga merupakan objek fungsi.
Fungsi adalah objek yang datang dengan JS. Ketika F1 dan F2 dibuat, JS akan secara otomatis membangun objek -objek ini melalui fungsi baru (). Oleh karena itu, ketiga objek ini dibuat melalui fungsi baru ().
Ada dua cara untuk membuat objek di JavaScript: Literal Objek dan Ekspresi Baru. Penciptaan O1 dan O2 hanya sesuai dengan dua cara ini. Mari kita fokus pada O3. Jika Anda menggunakan ide -ide Java dan C# untuk memahami, O3 adalah objek instance F1, dan O3 dan F1 adalah tipe yang sama. Setidaknya saya berpikir begitu sebelumnya, tetapi tidak ...
Jadi bagaimana Anda memahaminya? Ini sangat sederhana. Lihat apakah O3 dihasilkan melalui fungsi baru. Jelas tidak. Karena ini bukan objek fungsi, ini adalah objek biasa.
Setelah pemahaman sederhana tentang objek fungsi dan objek biasa, mari kita pelajari tentang prototipe dan rantai prototipe di JavaScript:
Dalam JS, setiap kali objek fungsi F1 dibuat, beberapa properti dibangun ke dalam objek, termasuk prototipe dan __proto__, prototipe adalah objek prototipe, yang mencatat beberapa properti dan metode F1.
Perlu dicatat bahwa prototipe tidak terlihat oleh F1, yaitu F1 tidak akan mencari properti dan metode dalam prototipe.
fungsi f () {} f.prototype.foo = "abc"; console.log (f.foo); //belum diartikanJadi, apa gunanya prototipe? Faktanya, fungsi utama prototipe adalah warisan. Dalam istilah awam, sifat dan metode yang didefinisikan dalam prototipe semuanya dibiarkan untuk "keturunan" mereka, sehingga subkelas dapat sepenuhnya mengakses properti dan metode dalam prototipe.
Untuk mengetahui bagaimana F1 meninggalkan prototipe untuk "keturunan", kita perlu memahami rantai prototipe di JS. Pada saat ini, __proto__ di JS telah memasuki pasar. Orang ini sangat aneh dan tersembunyi, sehingga Anda sering tidak melihatnya, tetapi ada di objek biasa dan objek fungsi. Fungsinya adalah menyimpan objek prototipe dari kelas induk. Ketika JS membuat objek melalui ekspresi baru, biasanya menetapkan prototipe kelas induk ke atribut __proto__ dari objek baru, yang membentuk generasi warisan ...
fungsi f () {} f.prototype.foo = "abc"; var obj = baru f (); console.log (obj.foo); // ABCSekarang kita tahu bahwa __proto__ dalam OBJ menyimpan prototipe f, jadi apa yang disimpan dalam __proto__ dalam prototipe F? Lihat gambar berikut:
Seperti yang ditunjukkan pada gambar, objek.prototype yang disimpan dalam __proto__ dari f.prototype, dan ada juga __proTo__ di objek.Prototipe objek., Dan dari hasil output, objek.prototype .__ Proto__ adalah nol, menunjukkan ujung rantai prototipe objek OBJ. Seperti yang ditunjukkan pada gambar di bawah ini:
Setelah objek OBJ memiliki rantai prototipe seperti itu, ketika obj.foo dieksekusi, OBJ akan menemukan apakah ia memiliki atribut, tetapi tidak akan menemukan prototipe sendiri. Ketika Foo tidak dapat ditemukan, OBJ akan mencari di sepanjang rantai prototipe ...
Dalam contoh di atas, kami mendefinisikan atribut FOO pada prototipe F, dan kemudian OBJ akan menemukan atribut ini pada rantai prototipe dan menjalankannya.