


Pemahaman mendalam tentang siri JavaScript (18): Pelaksanaan ECMAScript bagi pengaturcaraan berorientasikan objek_Pengetahuan asas
Pengenalan
Bab ini adalah bahagian kedua tentang pelaksanaan berorientasikan objek ECMAScript Dalam bahagian pertama, kami membincangkan pengenalan dan perbandingan CEMAScript Jika anda belum membaca bahagian pertama, sebelum meneruskan bab ini, saya amat mengesyorkan bahawa anda membaca bahagian pertama 1 artikel, kerana artikel ini terlalu panjang (35 halaman).
Teks asal bahasa Inggeris:http://dmitrysoshnikov.com/ecmascript/chapter-7-2-oop-ecmascript-implementation/
Nota: Oleh kerana panjangnya artikel ini, ralat tidak dapat dielakkan dan sentiasa disemak.
Dalam pengenalan, kami meluaskan kepada ECMAScript Sekarang, apabila kami mengetahui pelaksanaan OOPnya, mari kita takrifkannya dengan tepat:
ECMAScript ialah bahasa pengaturcaraan berorientasikan objek yang menyokong mewakilkan warisan berdasarkan prototaip.
ECMAScript ialah bahasa berorientasikan objek yang menyokong warisan delegasi berasaskan prototaip.
Kami akan menganalisisnya daripada jenis data yang paling asas Perkara pertama yang perlu difahami ialah ECMAScript menggunakan nilai dan objek primitif untuk membezakan entiti Oleh itu, apa yang dikatakan oleh beberapa artikel "Dalam JavaScript, semuanya adalah objek" adalah Salah (tidak cukup betul), nilai primitif ialah beberapa jenis data yang akan kita bincangkan di sini.
Jenis Data
Walaupun ECMAScript ialah bahasa ditaip secara dinamik yang lemah yang boleh menukar jenis secara dinamik, ia masih mempunyai jenis data. Dalam erti kata lain, objek mesti tergolong dalam jenis sebenar.
Terdapat 9 jenis data yang ditakrifkan dalam spesifikasi standard, tetapi hanya 6 yang boleh diakses secara langsung dalam program ECMAScript iaitu: Undefined, Null, Boolean, String, Number dan Object.
Tiga jenis lain hanya boleh diakses pada peringkat pelaksanaan (objek ECMAScript tidak boleh menggunakan jenis ini) dan digunakan dalam spesifikasi untuk menerangkan beberapa gelagat operasi dan menyimpan nilai perantaraan. 3 jenis ini ialah: Rujukan, Senarai dan Penyusunan.
Oleh itu, Rujukan digunakan untuk menerangkan operator seperti padam, jenis, dan ini, dan mengandungi objek asas dan nama sifat menerangkan kelakuan senarai parameter (dalam ungkapan baru dan panggilan fungsi); untuk menerangkan tingkah laku break, continue, return dan throw statement.
Jenis nilai primitif
Melihat kembali 6 jenis data yang digunakan dalam atur cara ECMAScript, 5 yang pertama ialah jenis nilai primitif, termasuk Undefined, Null, Boolean, String, Number dan Object.
Contoh jenis nilai primitif:
var a = undefined;
var b = null;
var c = benar;
var d = 'ujian';
var e = 10;
Nilai ini dilaksanakan secara langsung pada lapisan bawah Ia bukan objek, jadi tiada prototaip atau pembina.
Nota pakcik: Walaupun nilai asli ini serupa dengan nama yang biasa kita gunakan (Boolean, String, Number, Object), nilai tersebut bukanlah perkara yang sama. Oleh itu, keputusan typeof(true) dan typeof(Boolean) adalah berbeza, kerana hasil typeof(Boolean) ialah fungsi, jadi fungsi Boolean, String dan Number mempunyai prototaip (juga disebut dalam bab atribut membaca dan menulis di bawah) .
Jika anda ingin mengetahui jenis data itu, sebaiknya gunakan typeof Terdapat contoh yang perlu anda perhatikan Jika anda menggunakan typeof untuk menentukan jenis null, hasilnya adalah objek. kenapa? Kerana jenis null ditakrifkan sebagai Null.
alert(typeof null); // "objek"
Sebab "objek" dipaparkan adalah kerana spesifikasi menetapkan bahawa jenis nilai rentetan mengembalikan "objek" untuk nilai Null.
Spesifikasi tidak membayangkan untuk menerangkan perkara ini, tetapi Brendan Eich (pencipta JavaScript) mendapati bahawa null kebanyakannya digunakan di tempat objek muncul, berbanding undefined, seperti menetapkan objek kepada rujukan null. Walau bagaimanapun, sesetengah orang dalam beberapa dokumen mengaitkannya dengan pepijat, dan meletakkan pepijat dalam senarai pepijat yang Brendan Eich turut serta dalam perbincangan Hasilnya ialah keputusan jenis null telah ditetapkan untuk membantah (walaupun 262-3 The standard mentakrifkan bahawa jenis null ialah Null, dan 262-5 telah mengubah suai standard untuk mengatakan bahawa jenis null ialah objek).
Jenis objek
Seterusnya, jenis Objek (jangan dikelirukan dengan pembina Objek, kami hanya membincangkan jenis abstrak sekarang) ialah satu-satunya jenis data yang menerangkan objek ECMAScript.
Objek ialah koleksi tidak tertib pasangan nilai kunci.
Objek ialah koleksi tidak tertib pasangan nilai kunci
Nilai utama objek dipanggil atribut dan atribut ialah bekas untuk nilai primitif dan objek lain. Jika nilai atribut ialah fungsi, kami memanggilnya kaedah.
Contohnya:
var x = { // Objek "x" mempunyai 3 atribut: a, b, c
a: 10, // nilai asal
b: {z: 100}, // Objek "b" mempunyai atribut z
c: fungsi () { // fungsi (kaedah)
makluman('kaedah x.c');
}
};
makluman(x.a); // 10
alert(x.b); // [Objek objek]
makluman(x.b.z); // 100
x.c(); // 'kaedah x.c'
Dinamik
Seperti yang kami nyatakan dalam Bab 17, objek dalam ES adalah dinamik sepenuhnya. Ini bermakna kita boleh menambah, mengubah suai atau memadam sifat objek sesuka hati semasa program sedang dilaksanakan.
Contohnya:
var foo = {x: 10};
//Tambah atribut baharu
foo.y = 20;
console.log(foo); // {x: 10, y: 20}
// Ubah suai nilai atribut kepada fungsi
foo.x = fungsi () {
console.log('foo.x');
};
foo.x(); // 'foo.x'
// Padam atribut
padam foo.x;
console.log(foo); // {y: 20}
Sesetengah sifat tidak boleh diubah suai - (sifat baca sahaja, sifat dipadamkan atau sifat tidak boleh dikonfigurasikan). Kami akan menerangkannya kemudian dalam sifat atribut.
Selain itu, spesifikasi ES5 menetapkan bahawa objek statik tidak boleh dilanjutkan dengan sifat baharu dan halaman sifatnya tidak boleh dipadamkan atau diubah suai. Ia adalah apa yang dipanggil objek beku, yang boleh diperolehi dengan menggunakan kaedah Object.freeze(o).
var foo = {x: 10};
// Bekukan objek
Object.freeze(foo);
console.log(Object.isFrozen(foo)); // benar
// Tidak boleh diubah suai
foo.x = 100;
// Tidak boleh dikembangkan
foo.y = 200;
// Tidak boleh memadam
padam foo.x;
console.log(foo); // {x: 10}
Dalam spesifikasi ES5, kaedah Object.preventExtensions(o) juga digunakan untuk menghalang sambungan, atau kaedah Object.defineProperty(o) digunakan untuk menentukan sifat:
var foo = {x : 10};
Object.defineProperty(foo, "y", {
nilai: 20,
boleh ditulis: palsu, // baca sahaja
boleh dikonfigurasikan: palsu // Tidak boleh dikonfigurasikan
});
// Tidak boleh diubah suai
foo.y = 200;
// Tidak boleh memadam
padam foo.y; // palsu
// Sambungan Pencegahan dan Kawalan
Object.preventExtensions(foo);
console.log(Object.isExtensible(foo)); // false
//Tidak boleh menambah atribut baharu
foo.z = 30;
console.log(foo); {x: 10, y: 20}
Objek terbina dalam, objek asli dan objek hos
Perlu ambil perhatian bahawa spesifikasi juga membezakan antara objek terbina dalam, objek elemen dan objek hos.
Objek terbina dalam dan objek elemen ditakrifkan dan dilaksanakan oleh spesifikasi ECMAScript, dan perbezaan antara kedua-duanya adalah tidak ketara. Semua objek yang dilaksanakan oleh ECMAScript ialah objek asli (sesetengahnya adalah objek terbina dalam, sesetengahnya dicipta apabila program dilaksanakan, seperti objek yang ditentukan pengguna). Objek terbina dalam ialah subset objek asli yang dibina ke dalam ECMAScript sebelum program bermula (contohnya, parseInt, Match, dll.). Semua objek hos disediakan oleh persekitaran hos, biasanya penyemak imbas, dan mungkin termasuk tetingkap, amaran, dsb.
Perhatikan bahawa objek hos mungkin dilaksanakan oleh ES sendiri, mematuhi sepenuhnya semantik spesifikasi. Dari sudut pandangan ini, mereka boleh dipanggil objek "hos asli" (secepat mungkin secara teori), tetapi spesifikasi tidak mentakrifkan konsep objek "hos asli".
Objek Boolean, Rentetan dan Nombor
Selain itu, spesifikasi juga mentakrifkan beberapa kelas pembungkusan khas asli Objek ini ialah:
1. Objek Boolean
2. Objek rentetan
3. Objek digital
Objek ini dicipta melalui pembina terbina dalam yang sepadan dan mengandungi nilai asli sebagai sifat dalaman objek ini boleh menukar nilai primitif dan sebaliknya.
var c = Boolean baharu(benar);
var d = new String('test');
var e = Nombor baharu(10);
//Tukar kepada nilai asal
// Gunakan fungsi tanpa kata kunci baharu
с = Boolean(c);
d = Rentetan(d);
e = Nombor(e);
// Tukar semula kepada objek
с = Objek(c);
d = Objek(d);
e = Objek(e);
Selain itu, terdapat objek yang dicipta oleh pembina terbina dalam khas: Fungsi (pembina objek fungsi), Array (pembina tatasusunan) RegExp (pembina ungkapan biasa), Matematik (modul matematik), Tarikh (pembina tarikh) (bekas) , dsb. Objek ini juga merupakan nilai jenis objek Objek Perbezaannya antara satu sama lain diuruskan oleh sifat dalaman, yang kita bincangkan di bawah.
Tersurat
Untuk nilai tiga objek: objek, tatasusunan dan ungkapan biasa, mereka mempunyai pengecam singkatan yang dipanggil: pemula objek, pemula tatasusunan dan ungkapan biasa:
// Bersamaan dengan Tatasusunan baharu(1, 2, 3);
// Atau array = new Array();
// tatasusunan[0] = 1;
// tatasusunan[1] = 2;
// tatasusunan[2] = 3;
tatasusunan var = [1, 2, 3];
// Bersamaan dengan
// var object = new Object();
// object.a = 1;
// object.b = 2;
// object.c = 3;
objek var = {a: 1, b: 2, c: 3};
// Bersamaan dengan RegExp baharu("^\d $", "g")
var re = /^d $/g;
Perhatikan bahawa jika tiga objek di atas ditetapkan semula kepada jenis baharu, maka semantik pelaksanaan seterusnya akan digunakan mengikut jenis yang baru ditetapkan Contohnya, dalam pelaksanaan semasa Rhino dan versi lama SpiderMonkey 1.7, ia akan Objek berjaya dibuat menggunakan pembina kata kunci baharu, tetapi dalam beberapa pelaksanaan (pada masa ini Spider/TraceMonkey) semantik literal tidak semestinya berubah selepas jenis ditukar.
var getClass = Object.prototype.toString;
Objek = Nombor;
var foo = Objek baharu;
alert([foo, getClass.call(foo)]); // 0, "[Nombor objek]"
bar var = {};
// Rhino, SpiderMonkey 1.7 - 0, "[Nombor objek]"
// Lain-lain: masih "[objek objek]", "[objek objek]"
alert([bar, getClass.call(bar)]);
//Array mempunyai kesan yang sama
Tatasusunan = Nombor;
foo = Tatasusunan baharu;
alert([foo, getClass.call(foo)]); // 0, "[Nombor objek]"
bar = [];
// Rhino, SpiderMonkey 1.7 - 0, "[Nombor objek]"
// Lain-lain: masih "", "[Objek objek]"
alert([bar, getClass.call(bar)]);
// Tetapi untuk RegExp, semantik literal tidak diubah. semantik daripada literal
// tidak diubah dalam semua pelaksanaan yang diuji
RegExp = Nombor;
foo = RegExp baharu;
alert([foo, getClass.call(foo)]); // 0, "[Nombor objek]"
bar = /(?!)/g;
alert([bar, getClass.call(bar)]); // /(?!)/g, "[objek RegExp]"
Tersurat ungkapan biasa dan objek RegExp
Perhatikan bahawa dalam dua contoh berikut, semantik ungkapan biasa adalah setara dalam edisi ketiga spesifikasi Regexp literal hanya wujud dalam satu ayat dan dicipta dalam peringkat penghuraian, tetapi yang dicipta oleh pembina RegExp. ialah Ia adalah objek baharu, jadi ini mungkin menyebabkan beberapa masalah Sebagai contoh, nilai lastIndex adalah salah semasa ujian:
untuk (var k = 0; k < 4; k ) {
var re = /ecma/g;
makluman(re.lastIndex); // 0, 4, 0, 4
alert(re.test("ecmascript")); // benar, salah, benar, salah
}
// Bandingkan
untuk (var k = 0; k < 4; k ) {
var re = new RegExp("ecma", "g");
makluman(re.lastIndex); // 0, 0, 0, 0
alert(re.test("ecmascript")); // benar, benar, benar, benar
}
Nota: Walau bagaimanapun, masalah ini telah diperbetulkan dalam edisi ke-5 spesifikasi ES Sama ada ia berdasarkan literal atau pembina, peraturan biasa mencipta objek baharu.
Susun atur bersekutu
Pelbagai perbincangan statik teks, objek JavaScript (selalunya dibuat menggunakan pemula objek {}) dipanggil jadual cincang, jadual cincang atau nama mudah lain: cincang (konsep dalam Ruby atau Perl), Array pengurusan (konsep dalam PHP) , kamus (konsep dalam Python), dsb.
Hanya terdapat istilah sedemikian, terutamanya kerana strukturnya adalah serupa, iaitu, menggunakan pasangan "nilai-kunci" untuk menyimpan objek, yang benar-benar konsisten dengan struktur data yang ditakrifkan oleh teori "tatasusunan bersekutu" atau "cincang meja". Selain itu, jenis data abstrak jadual hash biasanya digunakan pada peringkat pelaksanaan.
Walau bagaimanapun, walaupun terminologi menerangkan konsep ini, ia sebenarnya satu kesilapan Dari perspektif ECMAScript: ECMAScript hanya mempunyai satu objek dan jenis serta subjenisnya, yang tidak berbeza daripada simpanan pasangan "nilai-kunci", jadi Terdapat. bukanlah konsep khusus mengenai perkara ini. Kerana sifat dalaman mana-mana objek boleh disimpan sebagai pasangan nilai kunci:
var a = {x: 10};
a['y'] = 20;
a.z = 30;
var b = Nombor baharu(1);
b.x = 10;
b.y = 20;
b['z'] = 30;
var c = Fungsi baharu('');
c.x = 10;
c.y = 20;
c['z'] = 30;
// Tunggu, subjenis mana-mana objek "subjenis"
Selain itu, memandangkan objek boleh kosong dalam ECMAScript, konsep "hash" juga tidak betul di sini:
Object.prototype.x = 10;
var a = {}; // Cipta "hash" kosong
alert(a["x"]); // 10, tetapi tidak kosong
alert(a.toString); // fungsi
a["y"] = 20; // Tambah pasangan nilai kunci baharu pada "cincang"
makluman(a["y"]); // 20
Object.prototype.y = 20; // Tambah atribut prototaip
padamkan ["y"]; // Padam
alert(a["y"]); // Tetapi kunci dan nilai di sini masih mempunyai nilai - 20
Sila ambil perhatian bahawa piawaian ES5 membenarkan kami mencipta objek tanpa prototaip (dilaksanakan menggunakan kaedah Object.create(null) Daripada perspektif ini, objek tersebut boleh dipanggil jadual cincang:
var aHashTable = Object.create(null);
console.log(aHashTable.toString); // Undefined
Selain itu, sesetengah sifat mempunyai kaedah pengambil/penetap khusus, jadi yang juga boleh menyebabkan kekeliruan tentang konsep ini:
var a = new String("foo");
a['panjang'] = 10;
makluman(a['panjang']); // 3
Walau bagaimanapun, walaupun dianggap bahawa "cincang" mungkin mempunyai "prototaip" (cth., kelas yang mewakilkan objek cincang dalam Ruby atau Python), dalam ECMAScript, istilah ini tidak betul kerana terdapat jurang antara kedua-dua perwakilan. Tiada perbezaan semantik (iaitu menggunakan notasi titik a.b dan a["b"] notasi).
Konsep dan semantik "atribut sifat" dalam ECMAScript tidak dipisahkan daripada "kunci", indeks tatasusunan dan kaedah Pembacaan dan penulisan sifat semua objek di sini mesti mengikut peraturan yang sama: semak rantai prototaip.
Dalam contoh Ruby berikut, kita dapat melihat perbezaan semantik:
a = {}
a.kelas # Hash
a.panjang # 0
# pasangan "nilai kunci" baharu
a['panjang'] = 10;
# Secara semantik, titik digunakan untuk mengakses sifat atau kaedah, bukan kunci
a.panjang # 1
#Pengindeks mengakses kunci dalam cincang
a['panjang'] # 10
# Ia serupa dengan mengisytiharkan kelas Hash secara dinamik pada objek sedia ada
# Kemudian isytiharkan sifat atau kaedah baharu
Hash kelas
def z
100
tamat
tamat
# Atribut baharu boleh diakses
a.z # 100
# Tetapi bukan "kunci"
a['z'] # tiada
Piawaian ECMA-262-3 tidak mentakrifkan konsep "cincang" (dan seumpamanya). Walau bagaimanapun, jika terdapat teori struktur sedemikian, adalah mungkin untuk menamakan objek itu selepasnya.
Penukaran objek
Untuk menukar objek kepada nilai primitif, anda boleh menggunakan kaedah valueOf Seperti yang kami katakan, apabila pembina fungsi dipanggil sebagai fungsi (untuk beberapa jenis), tetapi jika kata kunci baharu tidak digunakan, objek ditukar kepada nilai primitif , yang bersamaan dengan panggilan kaedah valueOf:
var a = Nombor baharu(1);
var primitiveA = Number(a); // Panggilan "valueOf" tersirat
var alsoPrimitiveA = a.valueOf(); // Panggilan eksplisit
makluman([
jenis a, // "objek"
jenis primitifA, // "nombor"
jenis jugaPrimitifA // "nombor"
]);
Pendekatan ini membenarkan objek untuk mengambil bahagian dalam pelbagai operasi, seperti:
var a = Nombor baharu(1);
var b = Nombor baharu(2);
makluman(a b); // 3
// Malah
var c = {
x: 10,
y: 20,
valueOf: function () {
Kembalikan this.x this.y;
}
};
var d = {
x: 30,
y: 40,
//Sama seperti valueOf fungsi c
valueOf: c.valueOf
};
makluman(c d); // 100
Nilai lalai valueOf akan berubah mengikut jenis objek (jika tidak dibatalkan untuk sesetengah objek, ia mengembalikan ini - contohnya: Object.prototype.valueOf(), dan nilai yang dikira : Date.prototype .valueOf() mengembalikan tarikh dan masa:
var a = {};
alert(a.valueOf() === a); // true, "valueOf" mengembalikan ini
var d = new Date();
alert(d.valueOf()); // masa
alert(d.valueOf() === d.getTime()); // true
Di samping itu, objek mempunyai perwakilan yang lebih primitif - perwakilan rentetan. Kaedah toString ini boleh dipercayai dan digunakan secara automatik untuk operasi tertentu:
var a = {
valueOf: function () {
Pulangan 100;
},
toString: fungsi () {
Kembalikan '__test';
}
};
// Dalam operasi ini, kaedah toString secara automatik dipanggil
makluman(a); // "__test"
// Tetapi di sini, kaedah valueOf() dipanggil
makluman(a 10); // 110
// Tetapi, setelah valueOf dipadamkan
// toString boleh dipanggil semula secara automatik
padamkan a.valueOf;
makluman(a 10); // "_test10"
Kaedah toString yang ditakrifkan pada Object.prototype mempunyai makna istimewa Ia mengembalikan nilai atribut [[Class]] dalaman yang akan kita bincangkan di bawah.
Berbanding dengan menukar kepada nilai primitif (ToPrimitive), menukar nilai kepada jenis objek juga mempunyai spesifikasi penukaran (ToObject).
Kaedah eksplisit ialah menggunakan pembina Objek terbina dalam sebagai fungsi untuk memanggil ToObject (agak serupa dengan kata kunci baharu):
var n = Objek(1); // [Nombor objek]
var s = Objek('ujian'); // [Rentetan objek]
//Sesuatu yang serupa, anda juga boleh menggunakan operator baharu
var b = Objek baharu(benar); // [objek Boolean]
// Jika parameter Objek baharu digunakan, objek mudah dicipta
var o = new Object(); // [objek Objek]
// Jika parameter ialah objek sedia ada
// Hasil penciptaan adalah dengan hanya mengembalikan objek
var a = [];
makluman(a === Objek baharu(a)); // benar
alert(a === Objek(a)); // true
Tiada peraturan am tentang memanggil pembina terbina dalam, sama ada menggunakan operator baharu atau tidak, ia bergantung kepada pembina. Contohnya, Tatasusunan atau Fungsi menghasilkan hasil yang sama apabila digunakan sebagai pembina menggunakan operator baharu atau fungsi mudah yang tidak menggunakan operator baharu:
var a = Array(1, 2, 3); // [Array objek]
var b = new Array(1, 2, 3); // [object Array]
var c = [1, 2, 3]; // [Array objek]
var d = Function(''); // [Fungsi objek]
var e = new Function(''); // [Fungsi objek]
Apabila sesetengah pengendali digunakan, terdapat juga beberapa penukaran tersurat dan tersirat:
var a = 1;
var b = 2;
// Tersirat
var c = a b; // 3, nombor
var d = a b '5' // "35", rentetan
// eksplisit
var e = '10'; // "10", rentetan
var f = e; // 10, nombor
var g = parseInt(e, 10); // 10, nombor
// Tunggu
Ciri-ciri atribut
Semua hartanah boleh mempunyai banyak atribut.
1.{ReadOnly} - Abaikan operasi tulis untuk memberikan nilai kepada harta, tetapi sifat baca sahaja boleh diubah oleh gelagat persekitaran hos - iaitu, ia bukan "nilai malar";
2.{DontEnum}——Atribut tidak boleh dihitung dengan for..in loop
3.{DontDelete}——Tingkah laku pengendali padam diabaikan (iaitu, ia tidak boleh dipadamkan);
4. {Internal} - Atribut dalaman, tiada nama (hanya digunakan pada peringkat pelaksanaan), atribut tersebut tidak boleh diakses dalam ECMAScript.
Perhatikan bahawa dalam ES5 {ReadOnly}, {DontEnum} dan {DontDelete} dinamakan semula kepada [[Boleh Ditulis]], [[Boleh Dihitung]] dan [[Boleh Dikonfigurasikan]], yang boleh dilalui secara manual melalui Object.defineProperty atau serupa kaedah untuk menguruskan hartanah ini.
var foo = {};
Object.defineProperty(foo, "x", {
nilai: 10,
boleh ditulis: benar, // iaitu {ReadOnly} = palsu
enumerable: false, // iaitu {DontEnum} = true
boleh dikonfigurasikan: benar // iaitu {DontDelete} = palsu
});
console.log(foo.x); // 10
// Dapatkan atribut set ciri
melalui deskriptor var desc = Object.getOwnPropertyDescriptor(foo, "x");
console.log(desc.enumerable); // palsu
console.log(desc.writable); // benar
// Tunggu
Sifat dalaman dan kaedah
Objek juga boleh mempunyai sifat dalaman (sebahagian daripada tahap pelaksanaan) yang tidak boleh diakses secara langsung kepada program ECMAScript (tetapi seperti yang akan kita lihat di bawah, sesetengah pelaksanaan membenarkan akses kepada beberapa sifat sedemikian). Sifat ini diakses melalui kurungan empat segi bersarang [[ ]]. Mari kita lihat beberapa daripada mereka Penerangan sifat ini boleh didapati dalam spesifikasi.
Setiap objek harus melaksanakan sifat dan kaedah dalaman berikut:
1.[[Prototaip]] - prototaip objek (akan diperkenalkan secara terperinci di bawah)
2.[[Kelas]] - perwakilan objek rentetan (contohnya, Tatasusunan Objek, Objek Fungsi, Fungsi, dsb.);
3.[[Dapatkan]]——Kaedah untuk mendapatkan nilai atribut
4.[[Put]]——Kaedah untuk menetapkan nilai atribut
5.[[CanPut]]——Periksa sama ada atribut boleh ditulis
6.[[HasProperty]]——Periksa sama ada objek sudah mempunyai sifat ini
7.[[Padam]]——Padamkan atribut daripada objek
8.[[DefaultValue]] mengembalikan nilai asal objek (memanggil kaedah valueOf, sesetengah objek mungkin membuang pengecualian TypeError).
Nilai sifat dalaman [[Kelas]] boleh diperoleh secara tidak langsung melalui kaedah Object.prototype.toString(), yang sepatutnya mengembalikan rentetan berikut: "[objek " [[Kelas]] "]" . Contohnya:
getClass.call({}); // [Objek objek]
getClass.call([]); // [Array objek]
getClass.call(Nombor baharu(1)); // [Nombor objek]
// Tunggu
alert(getClass.call(document.childNodes.item));
Pembina
Jadi, seperti yang kami nyatakan di atas, objek dalam ECMAScript dicipta melalui apa yang dipanggil pembina.Pembina ialah fungsi yang mencipta dan memulakan objek yang baru dibuat.
Pembina ialah fungsi yang mencipta dan memulakan objek yang baru dibuat.
Penciptaan objek (peruntukan memori) dijaga oleh kaedah dalaman pembina [[Construct]]. Tingkah laku kaedah dalaman ini ditakrifkan dengan baik, dan semua pembina menggunakan kaedah ini untuk memperuntukkan memori untuk objek baharu.
Perhatikan bahawa kod pengguna hanya boleh diakses semasa fasa permulaan, walaupun semasa fasa permulaan kita boleh mengembalikan objek lain (mengabaikan objek tihs yang dibuat dalam fasa pertama):
// Kemas kini objek yang baru dibuat
ini.x = 10;
// Tetapi ia mengembalikan objek yang berbeza
kembali [1, 2, 3];
}
var a = new A();
console.log(a.x, a); tidak ditentukan, [1, 2, 3]
F.[[Kelas]] = "Fungsi"
.... // Atribut lain
F.[[Panggilan]] =
F.[[Construct]] = internalConstructor // Pembina dalaman biasa
.... // Atribut lain
// Prototaip objek dicipta oleh pembina F
__objectPrototype = {};
__objectPrototype.constructor = F // {DontEnum}
F.prototaip = __objectPrototype
[[Panggil]] ] ialah cara utama untuk membezakan objek selain daripada atribut [[Kelas]] (di sini bersamaan dengan "Fungsi"), jadi atribut dalaman [[Panggil]] objek dipanggil sebagai fungsi. Menggunakan operator jenis pada objek sedemikian mengembalikan "fungsi". Walau bagaimanapun, ia berkaitan terutamanya dengan objek asli Dalam beberapa kes, pelaksanaan menggunakan typeof untuk mendapatkan nilai adalah berbeza. Contohnya: kesan window.alert (...) dalam IE:
// Dalam pelayar IE - "Objek", "objek", pelayar lain - "Fungsi", "fungsi"
alert(Object.prototype.toString.call(window.alert));
alert(typeof window.alert); // "Objek"
Kaedah dalaman [[Construct]] diaktifkan dengan menggunakan pembina dengan operator baharu Seperti yang kami katakan, kaedah ini bertanggungjawab untuk peruntukan memori dan penciptaan objek. Jika tiada parameter, kurungan untuk memanggil pembina juga boleh ditinggalkan:
fungsi A(x) { // pembina А
ini.x = x || 10;
}
// Jika tiada parameter diluluskan, kurungan boleh ditinggalkan
var a = new A; // atau new A();
makluman(a.x); // 10
//Lepaskan secara eksplisit dalam parameter x
var b = baharu A(20);
makluman(b.x); // 20
Kami juga tahu bahawa shis dalam pembina (fasa permulaan) ditetapkan kepada objek yang baru dibuat.
Mari kita kaji algoritma penciptaan objek.
Algoritma untuk penciptaan objek
Kelakuan kaedah dalaman [[Construct]] boleh diterangkan seperti berikut:
F.[[Construct]](initialParameters):
O = new NativeObject();
// Harta [[Kelas]] ditetapkan kepada "Objek"
O.[[Kelas]] = "Objek"
// Dapatkan objek g
apabila merujuk F.prototaip var __objectPrototype = F.prototype;
// Jika __objectPrototype ialah objek, maka:
O.[[Prototaip]] = __objectPrototype
// Jika tidak:
O.[[Prototaip]] = Objek.prototaip;
// Di sini O.[[Prototaip]] ialah prototaip objek Objek
// F.[[Panggilan]]
digunakan semasa memulakan objek yang baru dibuat. // Tetapkan ini kepada objek yang baru dibuat O
//Parameter adalah sama dengan initialParameters dalam F
R = F.[[Panggilan]](initialParameters); ini === O;
// Di sini R ialah nilai pulangan [[Panggil]]
// Lihat dalam JS, seperti ini:
// R = F.apply(O, initialParameters);
// Jika R ialah objek
kembalikan R
// Jika tidak
kembalikan O
Sila ambil perhatian dua ciri utama:
1. Pertama, prototaip objek yang baru dicipta diperoleh daripada atribut prototaip fungsi pada saat semasa (ini bermakna prototaip dua objek yang dicipta yang dicipta oleh pembina yang sama boleh berbeza kerana atribut prototaip bagi fungsinya juga boleh berbeza) .
2. Kedua, seperti yang kami nyatakan di atas, jika [[Panggil]] mengembalikan objek apabila objek dimulakan, ini betul-betul hasil yang digunakan untuk keseluruhan operator baharu:
fungsi A() {}
A.prototaip.x = 10;
var a = new A();
alert(a.x); // 10 – dapatkan
daripada prototaip
// Tetapkan sifat .prototype kepada objek baharu
// Mengapa mengisytiharkan sifat .constructor secara eksplisit dijelaskan di bawah
A.prototaip = {
pembina: A,
y: 100
};
var b = baru A();
// Objek "b" mempunyai sifat baharu
makluman(b.x); // tidak ditentukan
alert(b.y); // 100 – dapatkan
daripada prototaip
// Tetapi prototaip objek masih boleh mendapatkan hasil asal
alert(a.x); // 10 - dapatkan
daripada prototaip
fungsi B() {
ini.x = 10;
kembalikan Array baharu();
}
// Jika pembina "B" tidak kembali (atau mengembalikan ini)
// Kemudian objek ini boleh digunakan, tetapi dalam kes berikut, array
dikembalikan var b = B baharu();
makluman(b.x); // tidak ditentukan
alert(Object.prototype.toString.call(b)); // [Array objek]
Mari kita lihat dengan lebih dekat prototaip
Prototaip
Setiap objek mempunyai prototaip (kecuali beberapa objek sistem). Komunikasi prototaip dijalankan melalui sifat prototaip [[Prototaip]] dalaman, tersirat, dan tidak boleh diakses secara langsung Prototaip boleh menjadi objek atau nilai nol.
Pembina hartanah
Terdapat dua titik pengetahuan penting dalam contoh di atas Yang pertama adalah mengenai atribut prototaip atribut pembina fungsi Dalam algoritma penciptaan fungsi, kita tahu bahawa atribut pembina ditetapkan kepada atribut prototaip fungsi semasa fasa penciptaan fungsi , nilai atribut pembina adalah rujukan penting kepada fungsi itu sendiri:
fungsi A() {}
var a = new A();
alert(a.constructor); // fungsi A() {}, oleh delegasi
alert(a.constructor === A); // benar
Biasanya dalam kes ini, terdapat salah faham: sifat pembina pembina adalah salah sebagai harta objek yang baru dibuat itu sendiri, tetapi, seperti yang kita lihat, harta ini tergolong dalam prototaip dan diakses melalui warisan.
Dengan mewarisi contoh atribut pembina, anda secara tidak langsung boleh mendapatkan rujukan kepada objek prototaip:
fungsi A() {}
A.prototype.x = Nombor baharu(10);
var a = new A();
alert(a.constructor.prototype); // [Objek objek]
alert(a.x); // 10, melalui prototaip
// Kesan yang sama seperti a.[[Prototaip]].x
alert(a.constructor.prototype.x); // 10
alert(a.constructor.prototype.x === a.x); // true
Tetapi sila ambil perhatian bahawa atribut pembina dan prototaip fungsi boleh ditakrifkan semula selepas objek dicipta. Dalam kes ini, objek kehilangan mekanisme yang diterangkan di atas. Jika anda mengedit prototaip elemen melalui atribut prototaip fungsi (menambah objek baharu atau mengubah suai objek sedia ada), anda akan melihat atribut yang baru ditambah pada contoh itu.
Walau bagaimanapun, jika kita menukar sepenuhnya sifat prototaip fungsi (dengan memperuntukkan objek baharu), rujukan kepada pembina asal hilang, kerana objek yang kita cipta tidak termasuk harta pembina:
fungsi A() {}
A.prototaip = {
x: 10
};
var a = new A();
makluman(a.x); // 10
makluman(a.pembina === A); // palsu!
Oleh itu, rujukan prototaip kepada fungsi perlu dipulihkan secara manual:
fungsi A() {}
A.prototaip = {
pembina: A,
x: 10
};
var a = new A();
makluman(a.x); // 10
alert(a.constructor === A); // benar
Perhatikan bahawa walaupun atribut pembina telah dipulihkan secara manual, berbanding dengan prototaip asal yang hilang, ciri {DontEnum} tidak lagi tersedia, yang bermaksud pernyataan gelung for..in dalam A.prototype tidak disokong, tetapi dalam edisi ke-5 spesifikasi , menyediakan keupayaan untuk mengawal keadaan terbilang yang boleh dikira melalui atribut [[Enumerable]].
var foo = {x: 10};
Object.defineProperty(foo, "y", {
nilai: 20,
enumerable: false // aka {DontEnum} = true
});
console.log(foo.x, foo.y); // 10, 20
untuk (var k in foo) {
console.log(k); // hanya "x"
}
var xDesc = Object.getOwnPropertyDescriptor(foo, "x");
var yDesc = Object.getOwnPropertyDescriptor(foo, "y");
console.log(
xDesc.ennumerable, // benar
yDesc.enumerable // false
);
Prototaip eksplisit dan atribut [[Prototaip]] tersirat
Secara amnya, adalah tidak betul untuk merujuk prototaip objek secara eksplisit melalui atribut prototaip fungsi Ia merujuk kepada objek yang sama, atribut [[Prototaip]] objek:
a.[[Prototaip]] ----> Prototaip <---- A.prototaip
Selain itu, nilai [[Prototaip]] contoh sememangnya diperoleh daripada atribut prototaip pembina.
Walau bagaimanapun, penyerahan atribut prototaip tidak akan menjejaskan prototaip objek yang telah dibuat (ia hanya akan terjejas apabila atribut prototaip pembina berubah, maksudnya, hanya objek yang baru dibuat akan mempunyai prototaip baharu dan objek yang telah dibuat masih akan mempunyai prototaip baharu Rujukan kepada prototaip lama yang asal (prototaip ini tidak boleh diubah suai lagi).
// Situasi sebelum mengubah suai prototaip A.prototaip
a.[[Prototaip]] ----> Prototaip <---- A.prototaip
// Selepas pengubahsuaian
A.prototaip ----> Prototaip baharu // Objek baharu akan mempunyai prototaip ini
a.[[Prototaip]] ----> Prototaip // But prototaip asal
Contohnya:
fungsi A() {}
A.prototaip.x = 10;
var a = new A();
makluman(a.x); // 10
A.prototaip = {
pembina: A,
x: 20
y: 30
};
// Objek a ialah nilai yang diperoleh daripada prototaip minyak mentah melalui rujukan [[Prototaip]] tersirat
makluman(a.x); // 10
alert(a.y) // undefined
var b = baru A();
// Tetapi objek baharu ialah nilai yang diperoleh daripada prototaip baharu
makluman(b.x); // 20
makluman(b.y) // 30
Oleh itu, beberapa artikel mengatakan bahawa "mengubah suai prototaip secara dinamik akan menjejaskan semua objek dan semua objek akan mempunyai prototaip baharu" yang salah Prototaip baharu hanya akan berkuat kuasa pada objek yang baru dibuat selepas prototaip diubah suai.
Peraturan utama di sini ialah: prototaip objek dicipta apabila objek dibuat, dan tidak boleh diubah suai kepada objek baharu selepas itu Jika ia masih merujuk kepada objek yang sama, ia boleh dirujuk melalui prototaip eksplisit daripada pembina. Selepas objek dicipta, hanya sifat prototaip boleh ditambah atau diubah suai.
Atribut __proto__ bukan standard
Walau bagaimanapun, sesetengah pelaksanaan, seperti SpiderMonkey, menyediakan atribut eksplisit __proto__ bukan standard untuk merujuk prototaip objek:
fungsi A() {}
A.prototaip.x = 10;
var a = new A();
makluman(a.x); // 10
var __newPrototype = {
pembina: A,
x: 20,
y: 30
};
//Rujukan kepada objek baharu
A.prototaip = __newPrototype;
var b = baru A();
makluman(b.x); // 20
makluman(b.y); // 30
// Objek "a" masih menggunakan prototaip lama
makluman(a.x); // 10
makluman(a.y); // tidak ditentukan
// Ubah suai prototaip secara eksplisit
a.__proto__ = __newPrototype;
// Kini objek "а" merujuk kepada objek baharu
makluman(a.x); // 20
makluman(a.y); // 30
Ambil perhatian bahawa ES5 menyediakan kaedah Object.getPrototypeOf(O), yang secara langsung mengembalikan sifat [[Prototype]] objek - prototaip awal contoh. Walau bagaimanapun, berbanding __proto__, ia hanya pengambil dan tidak membenarkan nilai yang ditetapkan.
var foo = {};
Object.getPrototypeOf(foo) == Object.prototype; // true
Objek bebas daripada pembina
Oleh kerana prototaip contoh adalah bebas daripada pembina dan atribut prototaip pembina, pembina boleh dipadamkan selepas menyelesaikan kerja utamanya (membuat objek). Objek prototaip terus wujud dengan merujuk atribut [[Prototaip]]:
fungsi A() {}
A.prototaip.x = 10;
var a = new A();
makluman(a.x); // 10
// Set A kepada null - tunjukkan pembina rujukan
A = batal;
// Tetapi jika sifat .constructor tidak berubah,
// Anda masih boleh mencipta objek melaluinya
var b = new a.constructor();
makluman(b.x); // 10
// Rujukan tersirat juga dipadamkan
padamkan a.constructor.prototype.constructor;
padamkan b.constructor.prototype.constructor;
// Objek tidak boleh lagi dicipta melalui pembina A
// Tetapi kedua-dua objek ini masih mempunyai prototaip mereka sendiri
makluman(a.x); // 10
makluman(b.x); // 10
Ciri-ciri instanceof operator
Kami memaparkan prototaip rujukan melalui atribut prototaip pembina, yang berkaitan dengan pengendali instanceof. Operator ini berfungsi dengan rantai prototaip, bukan pembina Dengan mengambil kira perkara ini, selalunya berlaku salah faham apabila mengesan objek:
if (foo instanceof Foo) {
...
}
Ini tidak digunakan untuk mengesan sama ada objek foo dicipta menggunakan pembina Foo Semua instanceof operator hanya memerlukan satu sifat objek - foo.[[Prototaip]], dan semak kewujudannya bermula dari Foo.prototype dalam rantai prototaip. Operator instanceof diaktifkan melalui kaedah dalaman [[HasInstance]] dalam pembina.
Mari kita lihat contoh ini:
fungsi A() {}
A.prototaip.x = 10;
var a = new A();
makluman(a.x); // 10
makluman(contoh A); // benar
// Jika prototaip ditetapkan kepada null
A.prototaip = null;
// ..."a" masih boleh mengakses prototaip melalui a.[[Prototaip]]
makluman(a.x); // 10
// Walau bagaimanapun, instanceof operator tidak lagi boleh digunakan seperti biasa
// Kerana ia dilaksanakan daripada atribut prototaip pembina
alert(a instanceof A); // Ralat, A.prototype bukan objek
Sebaliknya, objek boleh dibuat oleh pembina, tetapi jika atribut [[Prototaip]] objek dan nilai atribut prototaip pembina ditetapkan kepada nilai yang sama, instanceof akan kembali benar apabila disemak:
fungsi B() {}
var b = B baharu();
makluman(b instanceof B); // benar
fungsi C() {}
var __proto = {
pembina: C
};
C.prototaip = __proto;
b.__proto__ = __proto;
makluman(b instanceof C); // benar
makluman(b instanceof B); // palsu
Prototaip boleh menyimpan kaedah dan berkongsi sifat
Prototaip digunakan dalam kebanyakan program untuk menyimpan kaedah objek, keadaan lalai dan sifat objek kongsi.
Sebenarnya, objek boleh mempunyai keadaannya sendiri, tetapi kaedahnya selalunya sama. Oleh itu, kaedah biasanya ditakrifkan dalam prototaip untuk pengoptimuman memori. Ini bermakna semua kejadian yang dibuat oleh pembina ini boleh berkongsi kaedah ini.
fungsi A(x) {
ini.x = x || 100;
}
A.prototaip = (fungsi () {
// Mulakan konteks
// Gunakan objek tambahan
var _someSharedVar = 500;
fungsi _someHelper() {
alert('pembantu dalaman: ' _someSharedVar);
}
kaedah fungsi1() {
makluman('kaedah1: ' ini.x);
}
kaedah fungsi2() {
makluman('kaedah2: ' ini.x);
_someHelper();
}
// Prototaip itu sendiri
Kembali {
pembina: A,
Kaedah1: kaedah1,
Kaedah2: kaedah2
};
})();
var a = baru A(10);
var b = baharu A(20);
a.method1(); // kaedah1: 10
a.method2(); // kaedah2: 10, pembantu dalaman: 500
b.method1(); // kaedah1: 20
b.method2(); // kaedah2: 20, pembantu dalaman: 500
// Kedua-dua objek menggunakan kaedah yang sama dalam prototaip
makluman(a.method1 === b.method1); // true
makluman(a.kaedah2 === b.kaedah2); // benar
Baca dan tulis atribut
Seperti yang kami nyatakan, membaca dan menulis nilai sifat adalah melalui kaedah dalaman [[Get]] dan [[Put]]. Kaedah dalaman ini diaktifkan melalui pengakses sifat: notasi titik atau notasi indeks:
// tulis
foo.bar = 10; // Dipanggil [[Put]]
console.log(foo.bar); // 10, dipanggil [[Dapatkan]]
console.log(foo['bar']); // Kesan yang sama
Mari lihat cara kaedah ini berfungsi dalam pseudokod:
Kaedah [[Dapatkan]]
[[Get]] juga akan menanyakan sifat daripada rantai prototaip, jadi sifat dalam prototaip juga boleh diakses melalui objek.
O.[[Dapatkan]](P):
// Jika ia adalah atribut anda sendiri, kembalikan
jika (O.hasOwnProperty(P)) {
Kembalikan O.P;
}
// Jika tidak, teruskan menganalisis prototaip
var __proto = O.[[Prototaip]];
// Jika prototaip adalah batal, kembalikan tidak ditentukan
// Ini mungkin: Object.prototype peringkat atas.[[Prototaip]] adalah batal
jika (__proto === null) {
Kembali tidak ditentukan;
}
// Jika tidak, panggil [[Get]] secara rekursif pada rantai prototaip dan cari atribut dalam prototaip setiap lapisan
// Sehingga prototaip adalah batal
kembalikan __proto.[[Dapatkan]](P)
Sila ambil perhatian bahawa [[Dapatkan]] juga akan kembali tidak ditentukan dalam situasi berikut:
if (window.someObject) {
...
}
Di sini, jika sifat someObject tidak ditemui dalam tetingkap, ia akan dicari dalam prototaip, kemudian dalam prototaip prototaip, dan seterusnya Jika ia tidak ditemui, undefined akan dikembalikan mengikut definisi.
Nota: Operator dalam juga boleh bertanggungjawab untuk mencari sifat (ia juga akan mencari rantai prototaip):
if ('someObject' dalam tetingkap) {
...
}
Ini membantu mengelakkan beberapa masalah khas: contohnya, walaupun someObject wujud, apabila someObject adalah sama dengan false, pusingan pertama pengesanan akan gagal.
Kaedah [[Put]]
Kaedah[[Put]] boleh mencipta dan mengemas kini sifat objek itu sendiri dan menutup sifat nama yang sama dalam prototaip.
O.[[Put]](P, V):
// Jika nilai tidak boleh ditulis pada atribut, keluar
jika (!O.[[CanPut]](P)) {
Kembali;
}
// Jika objek tidak mempunyai sifatnya sendiri, ciptakannya
// Semua atribut adalah palsu
jika (!O.hasOwnProperty(P)) {
createNewProperty(O, P, atribut: {
Baca Sahaja: palsu,
DontEnum: palsu,
JanganPadam: palsu,
Dalaman: palsu
});
}
// Tetapkan nilai jika atribut wujud, tetapi jangan ubah sifat atribut
O.P = V
kembali;
Contohnya:
Object.prototype.x = 100;
var foo = {};
console.log(foo.x); // 100, sifat warisan
foo.x = 10; // [[Letak]]
console.log(foo.x); // 10, atribut sendiri
padam foo.x;
console.log(foo.x); //set semula kepada 100, warisi sifat
Sila ambil perhatian bahawa sifat baca sahaja dalam prototaip tidak boleh ditutup dan keputusan tugasan akan diabaikan Ini dikawal oleh kaedah dalaman [[CanPut]].
// Contohnya, panjang atribut ialah baca sahaja, mari cuba tutup panjangnya
fungsi SuperString() {
/* tiada */
}
SuperString.prototype = new String("abc");
var foo = SuperString baharu();
console.log(foo.length); // 3, panjang "abc"
// Percubaan untuk menutup
foo.length = 5;
console.log(foo.length); // Pegun 3
Tetapi dalam mod ketat ES5, jika atribut baca sahaja bertopeng, TypeError akan disimpan.
Akses harta
Kaedah dalaman [[Get]] dan [[Put]] diaktifkan melalui notasi titik atau pengindeksan dalam ECMAScript Jika pengecam atribut ialah nama yang sah, ia boleh diakses melalui ".", dan pengindeksan Parti berjalan secara dinamik. nama yang ditentukan.
var a = {testProperty: 10};
alert(a.testProperty); // 10, klik
alert(a['testProperty']); // 10, indeks
var propertyName = 'Property';
alert(a['test' propertyName]); // 10, sifat dinamik diindeks
Terdapat ciri yang sangat penting di sini - pengakses harta sentiasa menggunakan spesifikasi ToObject untuk merawat nilai di sebelah kiri "." Penukaran tersirat ini berkaitan dengan pepatah "semuanya dalam JavaScript adalah objek" (namun, seperti yang kita sedia maklum, tidak semua nilai dalam JavaScript adalah objek).
Jika pengakses atribut digunakan untuk mengakses nilai asal, nilai asal akan dibalut oleh objek (termasuk nilai asal) sebelum mengakses, dan kemudian atribut akan diakses melalui objek yang dibalut selepas atribut diakses , objek yang dibalut akan dipadamkan.
Contohnya:
var a = 10; // Nilai asal
// Tetapi kaedah boleh diakses (sama seperti objek)
alert(a.toString()); // "10"
// Selain itu, kita boleh mencipta atribut jantung pada
a.test = 100; // Nampaknya tiada masalah
// Walau bagaimanapun, kaedah [[Dapatkan]] tidak mengembalikan nilai harta, tetapi mengembalikan tidak ditentukan
alert(a.test); // undefined
Jadi, mengapakah nilai asal dalam keseluruhan contoh boleh mempunyai akses kepada kaedah toString, tetapi bukan sifat ujian yang baru dibuat?
Jawapannya mudah:
Pertama sekali, seperti yang kami katakan, selepas menggunakan pengakses harta, ia bukan lagi nilai asal, tetapi objek perantaraan yang dibalut (keseluruhan contoh menggunakan Nombor(a) baharu), dan kaedah toString dihantar pada ini masa Ditemui dalam rantaian prototaip:
//Prinsip melaksanakan a.toString():
1. pembalut = Nombor baharu(a);
2. wrapper.toString(); // "10"
3. padamkan pembalut;
Seterusnya, apabila kaedah [[Put]] mencipta atribut baharu, ia juga dilakukan melalui objek berpakej:
//Prinsip melaksanakan a.test = 100:
1. pembalut = Nombor baharu(a);
2. wrapper.test = 100;
3. padamkan pembalut;
Kami melihat bahawa dalam langkah 3, objek yang dibalut dipadamkan dan halaman sifat yang baru dibuat dipadamkan - memadamkan objek pembalut itu sendiri.
Apabila menggunakan [[Get]] untuk mendapatkan nilai ujian, objek pembungkusan dicipta semula, tetapi kali ini objek yang dibalut tidak lagi mempunyai atribut ujian, jadi undefined dikembalikan:
//Prinsip melaksanakan a.test:
1. pembalut = Nombor baharu(a);
2. wrapper.test; // undefined
Kaedah ini menerangkan cara nilai asal dibaca Selain itu, jika sebarang nilai asal sering digunakan untuk mengakses atribut, pertimbangan kecekapan masa akan menggantikannya secara langsung dengan objek sebaliknya, jika ia tidak diakses dengan kerap, atau hanya digunakan Untuk tujuan pengiraan, borang ini boleh disimpan.
Warisi
Kami tahu bahawa ECMAScript menggunakan warisan delegasi berasaskan prototaip. Rantaian dan prototaip telah pun disebut dalam rantaian prototaip. Malah, semua pelaksanaan delegasi dan carian serta analisis rantaian prototaip dipekatkan ke dalam kaedah [[Get]].
Jika anda memahami sepenuhnya kaedah [[Dapatkan]], maka persoalan pewarisan dalam JavaScript akan menjadi penjelasan sendiri.
Apabila saya sering bercakap tentang warisan dalam JavaScript di forum, saya sentiasa menggunakan satu baris kod untuk menunjukkannya, sebenarnya, kita tidak perlu mencipta sebarang objek atau fungsi kerana bahasa itu sudah berdasarkan warisan adalah seperti berikut:
alert(1..toString()); // "1"
Kita sudah tahu cara kaedah [[Dapatkan]] dan pengakses harta berfungsi, mari lihat apa yang berlaku:
1 Mula-mula, buat objek pembungkusan daripada nilai asal 1 melalui Nombor(1)
baharu
2. Kemudian kaedah toString diwarisi daripada objek pembungkusan ini
Mengapa ia diwarisi? Oleh kerana objek dalam ECMAScript boleh mempunyai sifatnya sendiri, objek pembalut dalam kes ini tidak mempunyai kaedah toString. Jadi ia mewarisi daripada prinsip, iaitu Number.prototype.
Perhatikan terdapat kehalusan, dua titik dalam contoh di atas bukanlah ralat. Titik pertama mewakili bahagian perpuluhan dan titik kedua ialah pengakses atribut:
1.toString(); // Ralat sintaks!
(1).toString(); // OK
1..toString(); // OK
1['toString'](); // OK
Rantai Prototaip
Mari tunjukkan cara membuat rantai prototaip untuk objek yang ditentukan pengguna, ia sangat mudah:
fungsi A() {
makluman('A.[[Panggilan]] diaktifkan');
ini.x = 10;
}
A.prototaip.y = 20;
var a = new A();
makluman([a.x, a.y]); // 10 (diri), 20 (diwarisi)
fungsi B() {}
// Kaedah rantaian prototaip terbaharu adalah untuk menetapkan prototaip objek kepada objek baharu yang lain
B.prototaip = baru A();
// Baiki sifat pembina prototaip, jika tidak, ia akan menjadi A
B.prototype.constructor = B;
var b = B baharu();
makluman([b.x, b.y]); // 10, 20, 2 diwarisi
// [[Dapatkan]] b.x:
// b.x (tidak) -->
// b.[[Prototaip]].x (ya) - 10
// [[Dapatkan]] b.y
// b.y (tidak) -->
// b.[[Prototaip]].y (tidak) -->
// b.[[Prototaip]].[[Prototaip]].y (ya) - 20
// di mana b.[[Prototaip]] === B.prototaip,
// dan b.[[Prototaip]].[[Prototaip]] === A.prototaip
Kaedah ini mempunyai dua ciri:
Pertama, B.prototype akan mengandungi atribut x. Pada pandangan pertama ini mungkin kelihatan tidak betul, anda mungkin berfikir bahawa sifat x ditakrifkan dalam A dan bahawa pembina B menjangkakannya juga. Walaupun warisan prototaip tiada masalah dalam keadaan biasa, pembina B kadangkala tidak memerlukan atribut x Berbanding dengan warisan berasaskan kelas, semua atribut disalin ke subkelas turunan.
Walau bagaimanapun, jika terdapat keperluan (untuk mensimulasikan warisan berasaskan kelas) untuk menetapkan atribut x kepada objek yang dicipta oleh pembina B, terdapat beberapa cara, salah satunya akan kami tunjukkan kemudian.
Kedua, ini bukan ciri tetapi kelemahan - apabila prototaip subkelas dicipta, kod pembina juga dilaksanakan, dan kita dapat melihat bahawa mesej "A.[[Panggil]] diaktifkan" dipaparkan dua kali - Apabila menggunakan pembina A untuk mencipta objek dan menetapkannya kepada sifat B.prototype, adegan lain ialah apabila objek mencipta dirinya sendiri!
Contoh berikut adalah lebih kritikal, pengecualian yang dilemparkan oleh pembina kelas induk: Mungkin ia perlu diperiksa apabila objek sebenar dibuat, tetapi jelas, kes yang sama, iaitu, apabila menggunakan objek induk ini sebagai prototaip Sesuatu akan berlaku.
fungsi A(param) {
jika (!param) {
baling 'Param diperlukan';
}
this.param = param;
}
A.prototaip.x = 10;
var a = baru A(20);
makluman([a.x, a.param]); // 10, 20
fungsi B() {}
B.prototype = new A(); // Ralat
Selain itu, mempunyai terlalu banyak kod dalam pembina kelas induk juga merupakan satu kelemahan.
Untuk menyelesaikan "fungsi" dan masalah ini, pengaturcara menggunakan corak standard rantaian prototaip (ditunjukkan di bawah.
fungsi A() {
makluman('A.[[Panggilan]] diaktifkan');
ini.x = 10;
}
A.prototaip.y = 20;
var a = new A();
makluman([a.x, a.y]); // 10 (diri), 20 (bersepadu)
fungsi B() {
// Atau gunakan A.apply(this, arguments)
B.superproto.constructor.apply(this, arguments);
}
// Warisan: sambungkan prototaip bersama melalui pembina perantaraan kosong
var F = fungsi () {};
F.prot

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Pengenalan Dalam dunia digital yang berkembang pesat hari ini, adalah penting untuk membina aplikasi WEB yang mantap, fleksibel dan boleh diselenggara. Seni bina PHPmvc menyediakan penyelesaian yang ideal untuk mencapai matlamat ini. MVC (Model-View-Controller) ialah corak reka bentuk yang digunakan secara meluas yang memisahkan pelbagai aspek aplikasi kepada komponen bebas. Asas seni bina MVC Prinsip teras seni bina MVC ialah pengasingan kebimbangan: Model: merangkum data dan logik perniagaan aplikasi. Lihat: Bertanggungjawab untuk membentangkan data dan mengendalikan interaksi pengguna. Pengawal: Menyelaras interaksi antara model dan pandangan, mengurus permintaan pengguna dan logik perniagaan. Seni Bina PHPMVC Seni bina phpMVC mengikut corak MVC tradisional tetapi juga memperkenalkan ciri khusus bahasa. Berikut ialah PHPMVC

Prinsip SOLID ialah satu set prinsip panduan dalam corak reka bentuk pengaturcaraan berorientasikan objek yang bertujuan untuk meningkatkan kualiti dan kebolehselenggaraan reka bentuk perisian. Dicadangkan oleh Robert C. Martin, prinsip SOLID termasuk: Prinsip Tanggungjawab Tunggal (SRP): Kelas harus bertanggungjawab untuk hanya satu tugas, dan tugas ini harus dirangkumkan dalam kelas. Ini boleh meningkatkan kebolehselenggaraan dan kebolehgunaan semula kelas. classUser{private$id;private$name;private$email;publicfunction__construct($id,$nam

Dalam senario konkurensi tinggi pengaturcaraan berorientasikan objek, fungsi digunakan secara meluas dalam bahasa Go: Berfungsi sebagai kaedah: Fungsi boleh dilampirkan pada struktur untuk melaksanakan pengaturcaraan berorientasikan objek, mengendalikan data struktur dengan mudah dan menyediakan fungsi tertentu. Berfungsi sebagai badan pelaksanaan serentak: Fungsi boleh digunakan sebagai badan pelaksanaan goroutine untuk melaksanakan pelaksanaan tugas serentak dan meningkatkan kecekapan program. Berfungsi sebagai panggil balik: Fungsi boleh dihantar sebagai parameter kepada fungsi lain dan dipanggil apabila peristiwa atau operasi tertentu berlaku, menyediakan mekanisme panggil balik yang fleksibel.

Sambungan PHP boleh menyokong pengaturcaraan berorientasikan objek dengan mereka bentuk fungsi tersuai untuk mencipta objek, sifat akses dan kaedah panggilan. Mula-mula buat fungsi tersuai untuk membuat instantiate objek, dan kemudian tentukan fungsi yang mendapat sifat dan kaedah panggilan. Dalam pertempuran sebenar, kita boleh menyesuaikan fungsi untuk mencipta objek MyClass, mendapatkan atribut my_property dan memanggil kaedah my_methodnya.

Paradigma pengaturcaraan berorientasikan objek PHP memberikan kelebihan untuk pengurusan projek dan organisasi Dengan perkembangan pesat Internet, laman web dan aplikasi dari semua saiz telah muncul. Untuk memenuhi keperluan yang semakin meningkat dan meningkatkan kecekapan pembangunan dan kebolehselenggaraan, penggunaan pengaturcaraan berorientasikan objek (Pendek kata pengaturcaraan Berorientasikan Objek) telah menjadi arus perdana pembangunan perisian moden. Dalam bahasa skrip dinamik seperti PHP, OOP membawa banyak kelebihan kepada pengurusan dan organisasi projek

Apakah pengaturcaraan berorientasikan objek? Pengaturcaraan berorientasikan objek (OOP) ialah paradigma pengaturcaraan yang mengabstrak entiti dunia sebenar ke dalam kelas dan menggunakan objek untuk mewakili entiti ini. Kelas mentakrifkan sifat dan tingkah laku objek, dan objek memberi contoh kelas. Kelebihan utama OOP ialah ia menjadikan kod lebih mudah difahami, diselenggara dan digunakan semula. Konsep Asas OOP Konsep utama OOP termasuk kelas, objek, sifat dan kaedah. Kelas ialah pelan tindakan sesuatu objek, yang mentakrifkan sifat dan kelakuannya. Objek ialah contoh kelas dan mempunyai semua sifat dan tingkah laku kelas. Sifat ialah ciri-ciri objek yang boleh menyimpan data. Kaedah ialah fungsi objek yang boleh beroperasi pada data objek. Kelebihan OOP Kelebihan utama OOP termasuk: Kebolehgunaan semula: OOP boleh menjadikan kod lebih banyak

1. Pengenalan kepada Python Python ialah bahasa pengaturcaraan tujuan umum yang mudah dipelajari dan berkuasa Ia dicipta oleh Guido van Rossum pada tahun 1991. Falsafah reka bentuk Python menekankan kebolehbacaan kod dan menyediakan pembangun perpustakaan dan alatan yang kaya untuk membantu mereka membina pelbagai aplikasi dengan cepat dan cekap. 2. Sintaks asas Python Sintaks asas Python adalah serupa dengan bahasa pengaturcaraan lain, termasuk pembolehubah, jenis data, pengendali, penyataan aliran kawalan, dsb. Pembolehubah digunakan untuk menyimpan data Jenis data mentakrifkan jenis data yang boleh disimpan oleh pembolehubah. 3. Jenis data Python dalam Python

Pengaturcaraan Berorientasikan Fungsi dan Objek (OOP) menyediakan mekanisme pengaturcaraan yang berbeza dalam C++: Fungsi: blok bebas kod, memfokuskan pada melaksanakan tugas tertentu, tidak mengandungi data. OOP: Berdasarkan objek, kelas dan warisan, data dan tingkah laku dirangkumkan dalam objek. Dalam kes sebenar, kaedah fungsi untuk mengira luas segi empat sama adalah mudah dan langsung, manakala kaedah OOP merangkum data dan tingkah laku dan lebih sesuai untuk menguruskan interaksi objek. Memilih pendekatan yang sesuai bergantung pada senario: fungsi adalah baik untuk tugas bebas, OOP adalah baik untuk menguruskan interaksi objek yang kompleks.
