"prototype"
xususiyati JavaScript-ning o’zi tomonidan keng qo’llaniladi. Konstruktorning barcha funktsiyalari undan foydalanadi.
Avval oddiy narsalar uchun, keyin esa murakkab narsalar uchun qanday ekanligini bilib olamiz.
Object.prototype
Aytaylik, biz bo’sh obyektni chiqaramiz:
let obj = {};
alert(obj); // "[object Object]" ?
"[object Object]"
massivini yaratadigan kod qayerda? Bu o’rnatilgan toString
usuli, ammo u qayerda? Obj
bo’sh!
…Ammo obj = {}
qisqa yozuvi obj = new Object()
bilan bir xil, bu yerda Object
o’rnatilgan konstruktor funktsiyasi bo’lib, o’zining prototype
ga toString
bilan va boshqa usullar bilan ulkan obyektga murojaat qiladi.
Mana nima bo’lmoqda:
new Object()
deb nomlanganda (yoki {...}
so’zma-so’z obyekti yaratiladi), uning [[Prototype]]
biz muhokama qilgan qoidaga muvofiq Object.prototype
ga o’rnatiladi oldingi bobda muhokama qilindi:
Shunday qilib, obj.toString()
deb nomlanganda usul Object.prototype
dan olinadi.
Buni quyidagicha tekshirishimiz mumkin:
let obj = {};
alert(obj.__proto__ === Object.prototype); // true
alert(obj.toString === obj.__proto__.toString); //true
alert(obj.toString === Object.prototype.toString); //true
Iltimos, Object.prototype
ustidagi zanjirda qo’shimcha [[Prototype]]
mavjud emasligini unutmang:
alert(Object.prototype.__proto__); // null
Boshqa o’rnatilgan prototiplar
Array
, Date
, Function
va boshqa o’rnatilgan narsalar ham prototiplarda usullarni saqlaydi.
Masalan, [1, 2, 3]
massivini yaratganimizda, ichidagi sukut bo’yicha yangi new Array()
konstruktoridan foydalaniladi. Shunday qilib, massiv ma’lumotlari yangi obyektga yoziladi va Array.prototype
uning prototipiga aylanadi va usullarni taqdim etadi. Bu juda samarali xotira.
Spetsifikatsiya bo’yicha, barcha o’rnatilgan prototiplarning yuqori qismida Object.prototype
mavjud. Ba’zan odamlar “hamma narsa obyektlardan meros qilib oladi” deyishadi.
Bu yerda umumiy rasm (3 ta ichki o’rnatilgan bo’lishi uchun):
Keling, prototiplarni qo’lda tekshiramiz:
let arr = [1, 2, 3];
// u Array.prototype-dan meros qilib oladimi?
alert(arr.__proto__ === Array.prototype); // true
// keyin Object.prototype danmi?
alert(arr.__proto__.__proto__ === Object.prototype); // true
// va tepada null.
alert(arr.__proto__.__proto__.__proto__); // null
Prototiplardagi ba’zi usullar bir-biriga to’g’ri kelishi mumkin, masalan, Array.prototype
ning vergul bilan ajratilgan elementlarini sanab o’tadigan toString
ga ega:
let arr = [1, 2, 3];
alert(arr); // 1,2,3 <-- Array.prototype.toString natijasi
Avval ko’rganimizdek, Object.prototype
da toString
mavjud, ammo Array.prototype
zanjirda yaqinroq, shuning uchun massiv variantidan foydalaniladi.
Chrome-ning dasturchi konsoliga o’xshash brauzer vositalari merosni ham ko’rsatadi (console.dir
ichki obyektlar uchun ishlatilishi kerak bo’lishi mumkin):

Boshqa o’rnatilgan obyektlar ham xuddi shu tarzda ishlaydi. Hatto funktsiyalar – ular o’rnatilgan Function
konstruktorining obyektlari va ularning usullari (call
/apply
va boshqalar) Function.prototype
dan olingan. Funksiyalarda o’ziga xos toString
mavjud.
function f() {}
alert(f.__proto__ == Function.prototype); // true
alert(f.__proto__.__proto__ == Object.prototype); // true, obyektdan meros olish
Primitivlar
Eng murakkab narsa matnlar, raqamlar va mantiqiy turdagi qiymatlar bilan sodir bo’ladi.
Esimizda bo’lganidek, ular obyekt emas. Ammo biz ularning xususiyatlariga kirishga harakat qilsak, u holda vaqtinchalik o’rash moslamalari o’rnatilgan String
, Number
, Boolean
konstruktorlari yordamida yaratiladi, ular usullarni beradi va yo’qoladi.
Ushbu obyektlar biz uchun ko’rinmas tarzda yaratilgan va aksariyat interpretatorlar ularni optimallashtiradi, ammo spetsifikatsiya uni aynan shu tarzda tasvirlaydi. Ushbu obyektlarning usullari String.prototype
, Number.prototype
va Boolean.prototype
kabi prototiplarda mavjud.
null
vaundefined
qiymatlarida hech qanday moslama mavjud emasMahalliy prototiplarni o’zgartirish
Mahalliy prototiplarni o’zgartirish mumkin. Masalan, String.prototype
ga usul qo’shsak, u barcha matnlar uchun mavjud bo’ladi:
String.prototype.show = function() {
alert(this);
};
"BOOM!".show(); // BOOM!
Rivojlanish jarayonida biz xohlagan yangi o’rnatilgan usullar haqida g’oyalarimiz bo’lishi mumkin va ularni mahalliy prototiplarga qo’shishni xohlashimiz mumkin. Ammo bu umuman yomon fikr.
Prototiplar globaldir, shuning uchun ziddiyatni topish oson. Agar ikkita kutubxona String.prototype.show
usulini qo’shsa, ulardan biri boshqasining ustiga yoziladi.
Shunday qilib, odatda, mahalliy prototipni o’zgartirish yomon fikr deb hisoblanadi.
Zamonaviy dasturlashda mahalliy prototiplarni o’zgartirishni tasdiqlaydigan bitta holat mavjud. Bu juda ko’p to’ldirish.
Polyfilling – bu JavaScript spetsifikatsiyasida mavjud bo’lgan, ammo hozirgi JavaScript interpretatori tomonidan qo’llab-quvvatlanmagan usulning o’rnini bosuvchi so’z.
Keyin biz uni qo’lda amalga oshirishimiz va u bilan o’rnatilgan prototipni to’ldirishimiz mumkin.
Masalan:
if (!String.prototype.repeat) {
// agar bunday usul bo'lmasa
// uni prototipga qo'shing
String.prototype.repeat = function (n) {
// matni n marta takrorlang
// aslida, kod bundan biroz murakkabroq bo'lishi kerak
// (to'liq algoritm spetsifikatsiyada)
// ammo hatto nomukammal polyfill ham ko'pincha yetarlicha yaxshi deb hisoblanadi
return new Array(n + 1).join(this);
};
}
alert("La".repeat(3)); // LaLaLa
Prototiplardan qarz olish
Dekorativlar va ekspeditorlik, call/apply bobida biz qarz olish usuli haqida suhbatlashdik.
Ana shunda biz bir obyektdan usul olib, boshqasiga ko’chiramiz.
Mahalliy prototiplarning ba’zi usullari ko’pincha qarzga olinadi.
Masalan, agar biz massivga-o’xshash obyekt qilsak, unga ba’zi bir massiv usullarni ko’chirishni xohlashimiz mumkin.
Masalan:
let obj = {
0: "Hello",
1: "world!",
length: 2,
};
obj.join = Array.prototype.join;
alert( obj.join(',') ); // Hello,world!
U ishlaydi, chunki o’rnatilgan join
usulining ichki algoritmi faqat to’g’ri indekslar va length
xususiyati haqida qayg’uradi, chunki bu obyekt haqiqatan ham massiv ekanligini tekshirmaydi. Va ko’plab o’rnatilgan usullar shunga o’xshashdir.
Yana bir imkoniyat – obj.__proto__
ni Array.prototype
ga o’rnatish orqali meros olish, shunday qilib barcha Array
usullari avtomatik ravishda obj
da mavjud.
Ammo obj
boshqa obyektdan meros bo’lib qolgan bo’lsa, bu mumkin emas. Esingizda bo’lsa, biz bir vaqtning o’zida faqat bitta obyektdan meros olishimiz mumkin.
Qarz olish usullari moslashuvchan, agar kerak bo’lsa, turli xil narsalardan funksionallikni aralashtirishga imkon beradi.
Xulosa
- Barcha o’rnatilgan obyektlar bir xil shablonga amal qiladi:
- Usullar prototipda saqlanadi (
Array.prototype
,Object.prototype
,Date.prototype
). - Obyektning o’zi faqat ma’lumotlarni saqlaydi (massiv elementlari, obyekt xususiyatlari, sana).
- Usullar prototipda saqlanadi (
- Ibtidoiy usullar o’rash moslamalari prototiplarida ham saqlanadi:
Number.prototype
,String.prototype
,Boolean.prototype
. Faqatundefined
vanull
da o’rash moslamalari yo’q. - O’rnatilgan prototiplarni o’zgartirish yoki yangi usullar bilan to’ldirish mumkin. Ammo ularni o’zgartirish tavsiya etilmaydi. Ehtimol, bu faqat bitta ruxsat etilgan sabab – biz yangi standartni qo’shganimizda, ammo hali JavaScript-ni interpretatorda tomonidan qo’llab-quvvatlanmaganimizda.
Izohlar
<code>
yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>
yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepen…)