Ringkasan
Semua objek dalam JavaScript memiliki rantai warisan mereka sendiri. Artinya, setiap objek mewarisi objek lain, yang disebut objek "prototipe". Kecuali untuk NULL, ia tidak memiliki objek prototipe sendiri.
Pentingnya objek prototipe adalah bahwa jika objek A adalah prototipe objek B, objek B dapat memperoleh semua properti dan metode objek A. Objek.getPrototypof Metode digunakan untuk mendapatkan objek prototipe dari objek saat ini.
var p = objek.getPrototypeOf (OBJ);
Dalam kode di atas, objek P adalah objek prototipe objek OBJ.
Metode Object.Create digunakan untuk menghasilkan objek baru dan mewarisi objek yang ditentukan.
var obj = objek.create (p);
Dalam kode di atas, prototipe objek OBJ yang baru dihasilkan adalah objek p.
Atribut __proto__ non-standar (dua garis bawah di depan dan di belakang) dapat menulis ulang objek prototipe dari objek tertentu. Namun, Anda harus mencoba menggunakan properti ini sesedikit mungkin, tetapi gunakan Object.getPrototypeof () dan Object.setPrototypeOf () untuk membaca dan menulis objek prototipe.
var obj = {}; var p = {}; obj .__ proto__ = p; objek.getPrototypeof (obj) === p // trueKode di atas menetapkan objek P sebagai prototipe objek OBJ melalui atribut __proto__.
Ini adalah contoh praktis.
var a = {x: 1}; var b = {__proto__: a}; bx // 1Dalam kode di atas, objek B mengatur objek prototipe sebagai objek melalui atribut __proto__, sehingga objek B dapat memperoleh semua properti dan metode objek a. Objek B itu sendiri tidak memiliki atribut X, tetapi mesin JavaScript menemukan objek prototipe A melalui atribut __proto__, dan kemudian membaca atribut x a.
Perintah baru membuat objek instan baru melalui konstruktor. Ini pada dasarnya mengikat prototipe objek instan ke properti prototipe konstruktor, dan kemudian mengeksekusi konstruktor pada objek instan.
var o = foo baru (); // setara dengan var o = objek baru (); o .__ proto__ = foo.prototype; foo.call (o);
Atribut __proto__ Objek Prototipe sendiri juga dapat menunjuk ke objek lain, sehingga membentuk level "rantai prototipe" berdasarkan level.
var a = {x: 1}; var b = {__proto__: a}; var c = {__proTo__: b}; cx // 1Perlu dicatat bahwa mencari atribut tertentu dalam rantai prototipe berdampak pada kinerja. Semakin tinggi tingkat objek prototipe yang Anda cari, semakin besar dampaknya pada kinerja. Jika Anda mencari properti yang tidak ada, itu akan melintasi seluruh rantai prototipe.
Tindakan ini menunjuk
Di mana pun ini didefinisikan, ketika digunakan, selalu menunjuk pada objek saat ini, bukan objek prototipe.
var o = {a: 2, m: function (b) {return this.a + 1; }}; var p = object.create (o); pa = 12; pm () // 13Dalam kode di atas, metode M dari objek P berasal dari objek prototipe o. Pada saat ini, objek ini di dalam metode M tidak menunjuk ke O, tetapi untuk p.
Warisan konstruktor
Bagian ini memperkenalkan cara membuat satu konstruktor mewarisi konstruktor lain.
Asumsikan ada konstruktor bentuk.
bentuk fungsi () {this.x = 0; this.y = 0;} shape.prototype.move = function (x, y) {this.x += x; this.y += y; console.info ('bentuk dipindahkan.');}; konstruktor persegi panjang mewarisi bentuk. function rectangle () {shape.call (this); // Panggil Konstruktor Kelas Induk} // Cara lain untuk menulis fungsi rectangle () {this.base = bentuk; this.base ();} // Subkelas mewarisi metode kelas induk rectangle.prototype = object.create (shape.prototype); rect.prototype.constructor = rectangle; var rect = rectangle baru (); rect instance dari rectangle // truerect contoh bentuk // truerect.Kode di atas menunjukkan bahwa pewarisan konstruktor dibagi menjadi dua bagian, satu adalah bahwa subkelas memanggil metode konstruktor kelas induk, dan yang lainnya adalah bahwa prototipe subclass menunjuk ke prototipe kelas induk.
Dalam kode di atas, subclass mewarisi kelas induk secara keseluruhan. Terkadang, hanya warisan dari satu metode yang diperlukan, dan metode penulisan berikut dapat digunakan.
Classb.prototype.print = function () {classa.prototype.print.call (this); // beberapa kode}Dalam kode di atas, metode cetak Subclass B pertama -tama memanggil metode cetak Kelas A Induk A, dan kemudian menggunakan kodenya sendiri. Ini setara dengan mewarisi metode cetak kelas induk A.
Atribut __Proto__
Atribut __proto__ menunjuk ke objek prototipe dari objek saat ini, yaitu, atribut prototipe konstruktor.
var obj = objek baru (); obj .__ proto__ === objek.prototype // trueobj .__ proto__ === obj.constructor.prototype // true
Kode di atas pertama kali membuat objek baru OBJ, atribut __proto__ -nya, menunjuk ke atribut prototipe konstruktor (objek atau obj.constructor). Oleh karena itu, setelah membandingkan keduanya, return true.
Oleh karena itu, ada tiga cara untuk mendapatkan objek prototipe dari objek instance OBJ.
Di antara tiga metode di atas, dua yang pertama tidak terlalu dapat diandalkan. Standar ES6 terbaru menetapkan bahwa hanya browser yang perlu menggunakan atribut __proto__, dan lingkungan lain tidak dapat digunakan. Namun, obj.constructor.prototype mungkin gagal ketika secara manual mengubah objek prototipe.
var p = function () {}; var p = new p (); var c = function () {}; c.prototype = p; var c = new c (); c.constructor.prototype === p // falseDalam kode di atas, objek prototipe konstruktor C diubah menjadi P, dan hasilnya adalah bahwa C.Constructor.Prototype terdistorsi. Oleh karena itu, saat mengubah objek prototipe, atribut konstruktor harus diatur pada saat yang sama.
C.prototype = p; c.prototype.constructor = c; c.constructor.prototype === p // true
Oleh karena itu, disarankan untuk menggunakan objek ketiga.getPrototype dari metode untuk mendapatkan objek prototipe. Penggunaan metode ini adalah sebagai berikut.
var o = objek baru (); object.getPrototypeOf (o) === Object.prototype // true
Anda dapat menggunakan metode Object.getPrototypeOf untuk memeriksa apakah browser mendukung atribut __proTo__, yang tidak didukung oleh browser lama.
Object.getPrototypeof ({__proto__: null}) === nullKode di atas menetapkan atribut __proto__ dari suatu objek ke null, dan kemudian menggunakan objek.getPrototype dari metode untuk mendapatkan prototipe objek ini untuk menentukan apakah itu sama dengan nol. Jika lingkungan saat ini mendukung atribut __proto__, hasil perbandingan keduanya harus benar.
Dengan atribut __proTo__, mudah untuk mengatur prototipe objek instan. Misalkan ada tiga objek: mesin, kendaraan dan mobil, di mana mesin adalah prototipe kendaraan dan kendaraan adalah prototipe mobil, yang dapat diatur dengan hanya dua baris kode.
kendaraan .__ proto__ = mesin; mobil .__ proto__ = kendaraan;
Berikut ini adalah contoh. Properti yang ditentukan pada objek prototipe dibaca masing -masing melalui atribut __proto__ dan atribut konstruktor.prototype.
Array.prototype.p = 'abc'; var a = array baru (); a .__ proto __. p // abca.constructor.prototype.p // abc
Jelas, __proto__ terlihat sedikit lebih ringkas.
Ketika objek instan dihasilkan melalui konstruktor, atribut __proto__ dari objek instan secara otomatis menunjuk ke objek prototipe konstruktor.
var f = function () {}; var a = {}; f.prototype = a; var o = new f (); o .__ proto__ === a // trueWarisan atribut
Ada dua jenis atribut. Salah satunya adalah atribut asli dari objek itu sendiri, dan yang lainnya adalah atribut yang diwariskan yang diwarisi dari prototipe.
Sifat asli suatu objek
Semua properti objek itu sendiri dapat diperoleh dengan menggunakan Object.getOwnPropertynames.
Object.getOwnPropertynames (tanggal) // ["parse", "argumen", "utc", "penelepon", "nama", "prototipe", "sekarang", "panjang"]
Di antara sifat -sifat objek itu sendiri, beberapa dapat dihitung (dapat dihindarkan), sementara yang lain tidak dapat dihitung. Hanya dapatkan sifat -sifat yang dapat disebutkan, gunakan metode objek.keys.
Objek.keys (tanggal) // [] hasownproperty ()
Metode HasownProperty mengembalikan nilai boolean untuk menentukan apakah properti tertentu didefinisikan pada objek itu sendiri atau pada rantai prototipe.
Date.hasownproperty ('length') // truedate.hasownproperty ('tostring') // falseMetode HasownProperty adalah satu -satunya metode dalam JavaScript yang tidak melintasi rantai prototipe saat memproses sifat objek.
Sifat warisan suatu objek
Objek yang dibuat dengan Object.Create Metode akan mewarisi properti semua objek prototipe.
var proto = {p1: 123}; var o = objek.create (proto); o.p1 // 123o.hasownproperty ("p1") // falseDapatkan semua atribut
Untuk menentukan apakah suatu objek memiliki properti tertentu (apakah itu miliknya sendiri atau diwariskan), gunakan operator.
"Panjang" dalam tanggal // true "tostring" di tanggal // true
Dapatkan semua sifat yang dapat dihindarkan dari suatu objek (apakah itu sendiri atau diwariskan), dan Anda dapat menggunakan loop for-in.
var o1 = {p1: 123}; var o2 = object.create (o1, {p2: {value: "abc", enumerable: true}}); untuk (p dalam o2) {console.info (p);} // p2 // p1Untuk mendapatkan properti objek sendiri di untuk ... di loop, Anda dapat menggunakan metode HasownProperty untuk menilai.
untuk (nama var di objek) {if (object.hasownproperty (name)) { / * loop code * /}}Untuk mendapatkan semua sifat objek (apakah itu sendiri atau diwariskan, dan apakah itu dapat dihitung), Anda dapat menggunakan fungsi berikut.
Function inheritedPropernames (obj) {var props = {}; while (obj) {object.getOwnPropertynames (obj) .foreach (function (p) {props [p] = true;}); obj = objek.getPrototypeOf (obj); } return object.getOwnPropertynames (props);}Penggunaannya adalah sebagai berikut:
warisanPropertynames (tanggal) // ["penelepon", "konstruktor", "tostring", "utc", "call", "parse", "prototipe", "__definesetter__", "__lookupsetter__", "length", "argumen", "BIND", "__LOOKUPUPTER__", "PLANT", "ARGUMENT", "BIND", "__LOOKUPUPGETTER__", "ARGUMENT", "BIND", "__LOOKUPEPGETTER__" " "PropertyIseNumerable", "Valueof", "Apply", "__DefineGetter__", "Name", "Now", "HasownProperty"]
Salinan objek
Jika Anda ingin menyalin objek, Anda perlu melakukan dua hal berikut.
Pastikan objek yang disalin memiliki objek prototipe yang sama dengan objek asli.
Pastikan objek yang disalin memiliki sifat yang sama dengan objek asli.
Berikut ini adalah fungsi menyalin objek yang ditulis berdasarkan dua poin di atas.
function copyObject (orig) {var copy = object.create (object.getPrototypeOf (orig)); copyOwnProperties dari (salin, asal); return copy;} function copyOwnPropertiesFrom (target, sumber) {objek .getOwnPropertynames (sumber) .foreach (function (propkey) {var desc = object.getOwnPropertyDescriptor (sumber, propkey); objek.defineproperty (target, propkey, desc);}); mengembalikan target;}Warisan berganda
JavaScript tidak menyediakan fungsi warisan berganda, yaitu, itu tidak memungkinkan satu objek untuk mewarisi banyak objek pada saat yang sama. Namun, fungsi ini dapat dicapai melalui solusi.
fungsi m1 (prop) {this.hello = prop;} function m2 (prop) {this.world = prop;} fungsi s (p1, p2) {this.base1 = m1; this.base1 (p1); this.base2 = m2; this.base2 (p2);} s.prototype = baru m1 (); var s = baru s (111, 222); s.hello // 111s.world // 222Dalam kode di atas, subclass S mewarisi kelas induk M1 dan M2. Tentu saja, dari perspektif rantai warisan, S hanya memiliki satu kelas induk M1, tetapi karena pada contoh S, konstruktor M1 dan M2 dieksekusi pada saat yang sama, ia mewarisi metode kedua kelas ini pada saat yang sama.