Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. [[Prototype]] — yashirin havola
- 2.1 Prototipni ko'rish
- 2.2 Massiv va funksiyaning zanjiri
- 3. O'z zanjiringizni yasash
- 3.1 Object.create
- 3.2 Object.setPrototypeOf va literal ichida __proto__
- 3.3 Noto'g'ri prototip
- 4. Qidiruv qanday ishlaydi
- 5. Yozish zanjirga bormaydi
- 5.1 Soyalash
- 5.2 Tuzoq: prototipdagi massivni o'zgartirish
- 5.3 Prototip "jonli"
- 6. O'z va meros xususiyatlar
- 7. __proto__ — eskirgan eshik
- 8. Ko'p uchraydigan xatolar
- 8.1 Prototipdagi obyektni o'zgartirish
- 8.2 obj.prototype ni [[Prototype]] deb o'ylash
- 8.3 in bilan "o'zida bormi?" deb tekshirish
- 9. Mashqlar
- 1-mashq (oson): Qaysi qavatda?
- 2-mashq (o'rta): Umumiy savat
- 3-mashq (qiyin): Zanjir bo'ylab sayohat
- 4-mashq: Vazifalar qadami — nega in emas, Object.hasOwn?
- 10. Real ishda
- Xulosa
- Manbalar
JavaScript prototip va prototip zanjiri: xususiyat qayerdan topiladi
Qisqacha: Har obyektda yashirin
[[Prototype]]havolasi bor — boshqa obyektga yokinullga. Xususiyat obyektning o'zida topilmasa, JavaScript shu havola bo'ylab yuqoriga qidiradi: prototipda, keyin uning prototipida —nullga yetguncha. Shuning uchun{}datoString,[]damapbor. PrototipniObject.getPrototypeOf(obj)bilan ko'rasiz. O'qish zanjir bo'ylab yuradi, yozish esa doim obyektning o'ziga tushadi.
Bu darsda
[[Prototype]]nima ekanini va uniObject.getPrototypeOfbilan qanday ko'rishni bilasiz.- Xususiyat zanjir bo'ylab qanday qidirilishini qadamma-qadam tushuntira olasiz.
Object.createvaObject.setPrototypeOfbilan o'z zanjiringizni yasaysiz.- Soyalashni (shadowing) va prototipdagi massivni o'zgartirish tuzog'ini bilasiz.
in,for...in,Object.hasOwnvaObject.keysnega har xil javob berishini endi aniq tushunasiz.
Oldin bilishingiz kerak: Obyekt: kalit-qiymat juftliklari, Obyekt bo'ylab yurish, Havola semantikasi, call, apply, bind.
1. Nega bu kerak?
Kichik bir sirli holatdan boshlaymiz:
const choynak = { nom: "Choynak" };
console.log(choynak.toString()); // [object Object]
console.log("toString" in choynak); // true
console.log(Object.keys(choynak)); // [ 'nom' ]Biz choynak ga faqat nom ni yozdik. Object.keys ham buni tasdiqlaydi. Lekin toString metodi bor va ishlaydi. U qayerdan keldi?
08-qismda bu savolga bir necha marta duch keldik va har safar "meros" deb o'tib ketdik. Masalan, for...of va for...in darsida for...in massivda begona eslatma kalitini chiqardi. Keyin Obyekt darsida "toString" in choynak true berdi. So'ng Obyekt bo'ylab yurish darsida Object.create bilan yasalgan buyurtma o'zida yo'q valyuta ni ko'rsatdi. O'tgan darsda esa call va bind har funksiyada "o'z-o'zidan" bor edi.
Hammasining javobi bitta: prototip zanjiri. Bugun shu "meros" qutisini ochamiz.
Hayotdan o'xshatish. «Bahor»ga yangi ofitsiant keldi. Mehmon "Wi-Fi paroli qanday?" deb so'radi. Ofitsiant bilmaydi — u katta ofitsiant Otabekdan so'raydi. Otabek ham bilmasa — Jasur akadan. Jasur aka ham bilmasa — javob "bunday narsa yo'q". Har odam faqat o'zi biladigan narsani va kimdan so'rashni biladi. JavaScript obyekti ham xuddi shunday: o'zida yo'q narsani "kimdan so'rash kerakligini" biladi.
2. [[Prototype]] — yashirin havola
2.1 Prototipni ko'rish
Har obyektda ichki, ko'rinmas havola bor. Standartda u [[Prototype]] deb yoziladi. Ikki kvadrat qavs — "bu JavaScript dvigatelining ichki qismi, kodda bu nom bilan yozib bo'lmaydi" degan belgi.
Prototip (prototype) — obyekt o'zida topa olmagan xususiyatni qidirish uchun murojaat qiladigan boshqa obyekt. Ofitsiant uchun Otabek kabi.
Havolani o'qish uchun Object.getPrototypeOf(obyekt) bor:
const choynak = { nom: "Choynak" };
const proto = Object.getPrototypeOf(choynak);
console.log(proto === Object.prototype); // true
console.log(Object.hasOwn(proto, "toString")); // true
console.log(Object.getPrototypeOf(proto)); // nullUch qatorda uch fakt:
{ ... }bilan yasalgan har obyektning prototipi —Object.prototype. Bu JavaScript'ning tayyor obyekti, barcha oddiy obyektlarning umumiy "katta ofitsianti".toStringaynan shuObject.prototypening o'zida turibdi.choynak.toString()—choynakda topilmadi, prototipda topildi.Object.prototypening prototipi —null. Zanjir shu yerda tugaydi: "bunday narsa yo'q".
Object.prototype nomi biroz g'alati tuyulishi tabiiy: nuqta bor, demak bu Object ning prototype degan xususiyati. Ha, umumiy obyekt aynan shu yerda saqlanadi. Nega funksiyada prototype xususiyati bor — keyingi darsda ochamiz. Hozircha Object.prototype ni shunchaki "barcha oddiy obyektlarning umumiy prototipi"ning nomi deb qabul qiling. Array.prototype va Function.prototype ham xuddi shunday nomlar.
Object.prototype da toString dan tashqari yana o'n bir xususiyat bor: hasOwnProperty, valueOf, isPrototypeOf, constructor va boshqalar. Shuning uchun har oddiy obyektda ular "bepul" mavjud.
Maslahat:
console.log(Object.prototype)Node'da[Object: null prototype] {}chiqaradi. Qo'rqmang: bu "bo'sh obyekt" degani emas. Node shunchaki "bu obyektning o'z prototipinull" deb aytyapti. Ichidagi metodlar esa ko'rinmaydi, chunki ular "sanalmaydigan" qilib belgilangan (Xususiyat deskriptorlari).
2.2 Massiv va funksiyaning zanjiri
Massivning zanjiri bir bo'g'in uzunroq:
const taomlar = ["osh", "manti"];
const proto = Object.getPrototypeOf(taomlar);
console.log(proto === Array.prototype); // true
const yuqori = Object.getPrototypeOf(Array.prototype);
console.log(yuqori === Object.prototype); // true
console.log(taomlar.map === Array.prototype.map); // true
console.log(Object.hasOwn(taomlar, "map")); // falsemap, filter, push — barchasi Array.prototype da, bitta nusxada. Har massiv ularni o'zida saqlamaydi, prototipdan oladi. Yuzta massiv yarating — map baribir bitta. Bu xotirani tejaydi va barcha massivlar bir xil ishlashini kafolatlaydi.
Funksiyalar ham shunday. O'tgan darsda va'da qilingan javob:
function chekYoz() {}
const proto = Object.getPrototypeOf(chekYoz);
console.log(proto === Function.prototype); // true
console.log(Object.hasOwn(Function.prototype, "call")); // truecall, apply va bind — Function.prototype da. Har funksiya ularni shu yerdan oladi.
Uch zanjirni bitta sxemada ko'ring. Strelka — "topmasam, shundan so'rayman":
flowchart BT
CH["choynak"] --> OP["Object.prototype<br/>toString…"]
TA["taomlar"] --> AP["Array.prototype<br/>map, filter…"]
AP --> OP
FN["chekYoz"] --> FP["Function.prototype<br/>call, bind…"]
FP --> OP
OP --> N["null"]Hamma yo'l oxir-oqibat Object.prototype ga, undan keyin null ga olib boradi. Shuning uchun massivda ham, funksiyada ham toString va hasOwnProperty bor.
Tekshirib ko'ring:
[1, 2].hasOwnProperty("length")ishlaydimi?hasOwnPropertyqayerdan topiladi?
Javob
Ishlaydi va true qaytaradi. hasOwnProperty massivning o'zida yo'q, Array.prototype da ham yo'q — u ikki qadam yuqorida, Object.prototype da topiladi. length esa massivning o'z xususiyati, shuning uchun javob true.
3. O'z zanjiringizni yasash
3.1 Object.create
Obyekt bo'ylab yurish darsida Object.create(asos) ni ko'rgan edingiz: u prototipi asos bo'lgan yangi bo'sh obyekt yaratadi. Endi uni ongli ishlatamiz. «Bahor» taomlarining umumiy sozlamalari bitta obyektda tursin:
const asosiyTaom = { valyuta: "so'm", porsiya: 1 };
const osh = Object.create(asosiyTaom);
osh.nom = "Osh";
osh.narx = 35000;
console.log(osh); // { nom: 'Osh', narx: 35000 }
console.log(osh.valyuta); // so'm
console.log(Object.getPrototypeOf(osh) === asosiyTaom); // trueconsole.log(osh) faqat o'z xususiyatlarni ko'rsatdi. Lekin osh.valyuta ishladi — prototipdan. Object.create ning boshqa imkoniyatlarini Object.create va prototipal meros darsida ko'ramiz.
3.2 Object.setPrototypeOf va literal ichida __proto__
Mavjud obyektning prototipini keyin ham almashtirsa bo'ladi:
const asosiyTaom = { valyuta: "so'm" };
const choy = { nom: "Ko'k choy", narx: 5000 };
Object.setPrototypeOf(choy, asosiyTaom);
console.log(choy.valyuta); // so'mIshlaydi, lekin MDN bu haqda ochiq ogohlantiradi: prototipni "yashab turgan" obyektda almashtirish barcha brauzer va dvigatellarda juda sekin amal. Dvigatel obyektlar tuzilishini eslab qolib, kodni tezlashtiradi. Prototip o'zgarsa, bu tezlashtirishlar buziladi. Shuning uchun prototipni obyekt yaratilayotganda bering — Object.create bilan yoki literal ichida maxsus __proto__ kaliti bilan:
const asosiyTaom = { valyuta: "so'm" };
const lagmon = { __proto__: asosiyTaom, nom: "Lag'mon" };
console.log(lagmon.valyuta); // so'm
console.log(Object.keys(lagmon)); // [ 'nom' ]Literal ichidagi __proto__: — oddiy kalit emas, standartdagi maxsus yozuv: u xususiyat yaratmaydi, prototipni o'rnatadi. Object.keys da u ko'rinmadi. Bu yozuvni «__proto__ — eskirgan eshik» bo'limidagi eskirgan obj.__proto__ bilan adashtirmang.
3.3 Noto'g'ri prototip
Prototip faqat obyekt yoki null bo'lishi mumkin. Son bersangiz:
Object.setPrototypeOf({}, 5);TypeError: Object prototype may only be an Object or null: 5Tarjimasi: "Obyekt prototipi faqat obyekt yoki null bo'lishi mumkin: 5". Zanjirni aylana qilib ham bo'lmaydi — a ning prototipi b, b niki esa a bo'lsa, qidiruv hech qachon tugamasdi:
const a = {};
const b = Object.create(a);
Object.setPrototypeOf(a, b);TypeError: Cyclic __proto__ valueTarjimasi: "Aylanma __proto__ qiymati". Xabarda eski nom — __proto__ — ishlatilgan, lekin ma'nosi [[Prototype]]. Dvigatel aylanani oldindan tekshiradi va rad etadi.
Tekshirib ko'ring:
Object.create(asosiyTaom)va{ __proto__: asosiyTaom }— natijada farq bormi?
Javob
Yo'q: ikkalasi ham prototipi asosiyTaom bo'lgan yangi obyekt yaratadi. Farqi faqat yozuvda — literalga o'z xususiyatlarni ham shu zahoti yozish mumkin (nom: "Lag'mon"). Object.setPrototypeOf esa yangi obyekt yaratmaydi, mavjudini o'zgartiradi — shuning uchun sekin.
4. Qidiruv qanday ishlaydi
Endi asosiy mexanizmni qadamma-qadam ko'ramiz. Uch bo'g'inli zanjir: osh → asosiyTaom → umumiy → Object.prototype → null. To'rtta xususiyatni o'qiymiz — har biri boshqa qavatda topiladi (yoki topilmaydi):
const umumiy = { ishVaqti: "7:00–23:00" };
const asosiyTaom = Object.create(umumiy);
asosiyTaom.valyuta = "so'm";
const osh = Object.create(asosiyTaom);
osh.nom = "Osh";
console.log(osh.nom);
console.log(osh.valyuta);
console.log(osh.ishVaqti);
console.log(osh.chegirma);Konsolda:
Osh
so'm
7:00–23:00
undefinedKeyingi tugmasini bosib, har o'qishda qidiruv zanjirning qaysi bo'g'iniga yetib borishini kuzating:
Qidiruv qoidasi — uch qator:
- Xususiyat obyektning o'zida bormi? Bor — qiymatini qaytar.
- Yo'q —
[[Prototype]]ga o't va 1-qadamni takrorla. [[Prototype]]—nullbo'lsa, qidiruv tugadi:undefined.
Bu scope zanjiri ga juda o'xshaydi: o'zgaruvchi ichki scope'da topilmasa, tashqisiga qaraladi. Farqi: scope zanjiri o'zgaruvchilar uchun va kod qayerda yozilganiga qarab quriladi. Prototip zanjiri esa obyekt xususiyatlari uchun va obyektlar o'rtasidagi havolalardan iborat.
Topilmagan xususiyat undefined beradi, xato emas. Xato faqat keyingi qadamda chiqadi — undefined ning xususiyatini o'qisangiz yoki uni funksiyadek chaqirsangiz.
Tekshirib ko'ring: Shu zanjirda
osh.toStringqayerdan topiladi? Necha qadam kerak bo'ladi?
Javob
Object.prototype dan, to'rtinchi qadamda: osh → asosiyTaom → umumiy → Object.prototype. umumiy { ... } literal bilan yasalgan, demak uning prototipi Object.prototype. Shu tufayli zanjirdagi har obyektda toString bor.
5. Yozish zanjirga bormaydi
5.1 Soyalash
O'qish zanjir bo'ylab yuqoriga yuradi. Yozish esa yo'q: obj.x = ... doim obj ning o'ziga yozadi.
const asosiyTaom = { valyuta: "so'm" };
const osh = Object.create(asosiyTaom);
osh.valyuta = "dollar";
console.log(osh.valyuta, asosiyTaom.valyuta); // dollar so'm
delete osh.valyuta;
console.log(osh.valyuta); // so'mosh.valyuta = "dollar" prototipni o'zgartirmadi. U osh ning o'zida yangi valyuta yaratdi. Endi qidiruv 1-qadamda to'xtaydi va prototipdagi valyuta ga yetib bormaydi — u "soyada" qoldi. Bu soyalash (shadowing): o'z xususiyati prototipdagi xuddi shu nomli xususiyatni to'sib qo'yadi. Scope asoslari darsidagi o'zgaruvchi soyalashi bilan bir g'oya. delete osh.valyuta o'z xususiyatini o'chirdi — soya ketdi va prototipdagisi yana ko'rindi.
Bu juda foydali: umumiy qiymat prototipda turadi, alohida obyekt esa uni o'zi uchun "qayta yozadi". Boshqa obyektlarga ta'sir qilmaydi.
5.2 Tuzoq: prototipdagi massivni o'zgartirish
Endi xavfli holat. Prototipda massiv bo'lsin:
const asosiyTaom = { teglar: [] };
const osh = Object.create(asosiyTaom);
const manti = Object.create(asosiyTaom);
osh.teglar.push("issiq");
console.log(manti.teglar); // [ 'issiq' ]
console.log(Object.hasOwn(osh, "teglar")); // falseBiz faqat oshga teg qo'shdik — mantida ham paydo bo'ldi! Sabab: osh.teglar.push(...) — bu yozish emas, avval o'qish. osh.teglar ni o'qish zanjir bo'ylab ketdi va prototipdagi massivni topdi. push esa o'sha umumiy massivni o'zgartirdi (Havola semantikasi). osh ning o'zida teglar umuman paydo bo'lmadi.
Qoida: prototipda faqat metodlar va o'zgarmaydigan umumiy qiymatlar tursin. Har obyektga xos holat — massiv, obyekt, hisoblagich — obyektning o'zida bo'lsin. Buni qanday qilish — keyingi darsdagi konstruktor funksiya ning asosiy vazifasi.
5.3 Prototip "jonli"
Prototip — oddiy obyekt, uni istalgan payt o'zgartirish mumkin. O'zgarishni unga bog'langan hamma obyekt darhol ko'radi:
const asosiyTaom = { valyuta: "so'm" };
const osh = Object.create(asosiyTaom);
asosiyTaom.ishVaqti = "7:00–23:00";
console.log(osh.ishVaqti); // 7:00–23:00osh ishVaqti qo'shilishidan oldin yaratilgan edi, lekin uni ko'rdi. Chunki osh prototipning nusxasini emas, havolasini saqlaydi. Har o'qishda qidiruv prototipga qaytadan boradi. 08-qismdagi Array.prototype.eslatma = "salom" shuning uchun barcha massivlarda paydo bo'lgan edi. O'rnatilgan prototiplarni o'zgartirish nega xavfli ekanini O'rnatilgan prototiplar darsida ko'ramiz.
Tekshirib ko'ring:
osh.teglar = ["issiq"](push emas, tayinlash) yozilganida,manti.teglaro'zgarardimi?
Javob
Yo'q. Tayinlash — yozish, u doim osh ning o'ziga tushadi. osh da yangi teglar paydo bo'ladi va prototipdagisini soyalaydi. manti.teglar esa prototipdagi bo'sh massiv bo'lib qoladi. Farq push (o'qib, keyin o'zgartirish) va = (yozish) o'rtasida.
6. O'z va meros xususiyatlar
Endi 08-qismdagi to'rt vositaning farqi oxirigacha tushunarli bo'ladi:
const asosiyTaom = { valyuta: "so'm" };
const osh = Object.create(asosiyTaom);
osh.nom = "Osh";
console.log(Object.hasOwn(osh, "valyuta")); // false
console.log("valyuta" in osh); // true
console.log(Object.keys(osh)); // [ 'nom' ]
for (const kalit in osh) {
console.log(kalit);
}Konsolda:
false
true
[ 'nom' ]
nom
valyuta| Vosita | Qayerga qaraydi | valyuta (meros) |
|---|---|---|
Object.hasOwn(obj, k) |
faqat o'zi | false |
k in obj |
butun zanjir | true |
Object.keys(obj) |
faqat o'zi | yo'q |
for...in |
butun zanjir | bor |
in va for...in zanjir bo'ylab yuradi. Object.hasOwn, Object.keys, Object.values, Object.entries va console.log esa faqat obyektning o'ziga qaraydi.
Nega for...in toString ni chiqarmadi? U ham zanjirda-ku. Chunki for...in faqat sanaladigan (enumerable) kalitlarni ko'rsatadi. O'rnatilgan metodlar — toString, map, push — sanalmaydigan qilib belgilangan. Siz = bilan qo'shgan xususiyat esa sanaladigan bo'ladi. 08-qismdagi Array.prototype.eslatma shuning uchun for...in da chiqqan, map esa chiqmagan.
Amaliy xulosa: obyekt kalitlari bo'ylab yurish uchun Object.keys yoki Object.entries ishlating (Obyekt bo'ylab yurish). "Bu kalit o'zida bormi?" degan savolga — Object.hasOwn.
Tekshirib ko'ring: Shu
oshuchunObject.entries(osh)nima qaytaradi? Undavalyutabormi?
Javob
[ [ 'nom', 'Osh' ] ] — faqat bitta juftlik. Object.entries ham Object.keys kabi faqat obyektning o'z xususiyatlariga qaraydi. valyuta prototipda, shuning uchun u ro'yxatga kirmaydi — garchi osh.valyuta o'qilsa, "so'm" qaytsa ham.
7. __proto__ — eskirgan eshik
Eski kodda va internetdagi maqolalarda obj.__proto__ ni ko'p uchratasiz:
const asosiyTaom = { valyuta: "so'm" };
const osh = Object.create(asosiyTaom);
console.log(osh.__proto__ === asosiyTaom); // true__proto__ (ikki pastki chiziq bilan) — [[Prototype]] ni o'qish va yozish uchun eski "eshik". U brauzerlarda tarixan paydo bo'lgan, keyin moslik uchun standartga kiritilgan, lekin eskirgan (deprecated) deb belgilangan. Hozir ham ishlaydi, lekin yangi kodda yozmang:
| Eski | Zamonaviy |
|---|---|
obj.__proto__ |
Object.getPrototypeOf(obj) |
obj.__proto__ = p |
Object.setPrototypeOf(obj, p) |
| — | Object.create(p) — yaratishda |
Bitta qiziq fakt: __proto__ ning o'zi ham Object.prototype dagi xususiyat — o'sha 12 tadan biri. Ya'ni osh.__proto__ ham zanjir bo'ylab qidiruv bilan topiladi. Prototipi null bo'lgan obyektda bu "eshik" umuman yo'q. Bunday obyektlarni Object.create darsida ko'ramiz.
__proto__ ning yana bir xavfli tomoni bor. Agar foydalanuvchidan kelgan kalit ("__proto__") obyektga ehtiyotsiz yozilsa, u oddiy xususiyat emas, prototipni o'zgartiradi. Bu hujum — Prototype pollution darsining mavzusi.
Brauzerda zanjirni ko'z bilan ham ko'rish mumkin. Chrome konsolida console.log(osh) ni yozib, obyektni oching — eng pastda [[Prototype]] qatori turadi. Uni ochsangiz, prototipning xususiyatlari va uning o'z [[Prototype]] i ko'rinadi. Node konsoli esa faqat o'z xususiyatlarni chiqaradi (console API).
8. Ko'p uchraydigan xatolar
8.1 Prototipdagi obyektni o'zgartirish
«Tuzoq: prototipdagi massivni o'zgartirish» bo'limidagi osh.teglar.push(...). Xato xabari chiqmaydi — barcha obyektlar jimgina bitta massivni bo'lishadi. Tuzatish: har obyektga o'z massivini bering: osh.teglar = [], keyin push.
8.2 obj.prototype ni [[Prototype]] deb o'ylash
const asosiyTaom = { valyuta: "so'm" };
const osh = Object.create(asosiyTaom);
console.log(osh.prototype); // undefined
console.log(Object.getPrototypeOf(osh) === asosiyTaom); // trueosh.prototype — undefined. [[Prototype]] — oddiy xususiyat emas, uni nuqta bilan o'qib bo'lmaydi. prototype nomli xususiyat esa faqat funksiyalarda bor va u butunlay boshqa narsa. Bu chalkashlikni keyingi darsda oxirigacha yechamiz. Tuzatish: prototipni faqat Object.getPrototypeOf(obj) bilan oling.
8.3 in bilan "o'zida bormi?" deb tekshirish
"toString" in buyurtma doim true — har obyektda bor. Foydalanuvchi kiritgan kalitni in yoki obj[kalit] !== undefined bilan tekshirish shuning uchun xavfli. Tuzatish: Object.hasOwn(obj, kalit). vazifalar dagi filtr tekshiruvi aynan shunday yozilgan — «Vazifalar qadami» da nega ekanini ko'ramiz.
9. Mashqlar
1-mashq (oson): Qaysi qavatda?
Kodni ishga tushirmasdan, har qator nima chiqarishini yozing.
const zal = { stollar: 20, valyuta: "so'm" };
const kichikZal = Object.create(zal);
kichikZal.stollar = 6;
console.log(kichikZal.stollar);
console.log(kichikZal.valyuta);
console.log(Object.hasOwn(kichikZal, "valyuta"));
console.log(zal.stollar);Yechim
const zal = { stollar: 20, valyuta: "so'm" };
const kichikZal = Object.create(zal);
kichikZal.stollar = 6;
console.log(kichikZal.stollar); // 6
console.log(kichikZal.valyuta); // so'm
console.log(Object.hasOwn(kichikZal, "valyuta")); // false
console.log(zal.stollar); // 20kichikZal.stollar = 6 — o'ziga yozildi va prototipdagi 20 ni soyaladi. valyuta — prototipdan, shuning uchun hasOwn — false. zal o'zgarmadi: yozish zanjirga bormaydi.
2-mashq (o'rta): Umumiy savat
Ikki stolning buyurtmalari aralashib ketyapti. Xatoni toping va tuzating: 1-stolda faqat Osh, 5-stolda faqat Manti bo'lsin. asosiyStol dagi umumiy valyuta esa prototipda qolsin.
const asosiyStol = { valyuta: "so'm", taomlar: [] };
const stol1 = Object.create(asosiyStol);
const stol5 = Object.create(asosiyStol);
stol1.taomlar.push("Osh");
stol5.taomlar.push("Manti");
console.log(stol1.taomlar, stol5.taomlar);Yechim
const asosiyStol = { valyuta: "so'm" };
const stol1 = Object.create(asosiyStol);
stol1.taomlar = [];
const stol5 = Object.create(asosiyStol);
stol5.taomlar = [];
stol1.taomlar.push("Osh");
stol5.taomlar.push("Manti");
console.log(stol1.taomlar, stol5.taomlar); // [ 'Osh' ] [ 'Manti' ]
console.log(stol1.valyuta); // so'mXatoli kodda ikkala push ham prototipdagi bitta massivga yozgan va natija [ 'Osh', 'Manti' ] [ 'Osh', 'Manti' ] bo'lgan. Endi har stolning o'z massivi bor, umumiy valyuta esa prototipda. Har obyektga o'z massivini qo'lda berish noqulay — keyingi darsdagi konstruktor funksiya buni avtomatlashtiradi.
3-mashq (qiyin): Zanjir bo'ylab sayohat
Ikki funksiya yozing:
zanjirUzunligi(obyekt)— obyektdannullgacha nechta prototip borligini qaytarsin.{}uchun1,[]uchun2.qayerda(obyekt, kalit)— kalit zanjirning qaysi qavatida topilishini qaytarsin:0— obyektning o'zida,1— prototipida,2— prototipining prototipida; topilmasa —-1.
Ishora: while sikli, Object.getPrototypeOf va Object.hasOwn. Sikl null ga yetganda to'xtasin.
Yechim
function zanjirUzunligi(obyekt) {
let soni = 0;
let joriy = Object.getPrototypeOf(obyekt);
while (joriy !== null) {
soni++;
joriy = Object.getPrototypeOf(joriy);
}
return soni;
}
function qayerda(obyekt, kalit) {
let qavat = 0;
let joriy = obyekt;
while (joriy !== null) {
if (Object.hasOwn(joriy, kalit)) {
return qavat;
}
qavat++;
joriy = Object.getPrototypeOf(joriy);
}
return -1;
}
const umumiy = { ishVaqti: "7:00–23:00" };
const asosiyTaom = Object.create(umumiy);
asosiyTaom.valyuta = "so'm";
const osh = Object.create(asosiyTaom);
osh.nom = "Osh";
console.log(zanjirUzunligi({}), zanjirUzunligi([])); // 1 2
console.log(zanjirUzunligi(osh)); // 3
console.log(qayerda(osh, "nom"), qayerda(osh, "ishVaqti")); // 0 2
console.log(qayerda(osh, "toString")); // 3
console.log(qayerda([], "map"), qayerda(osh, "chegirma")); // 1 -1qayerda — JavaScript dvigateli har obj.kalit o'qishda bajaradigan qidiruvning aynan o'zi, faqat qiymat o'rniga qavat raqamini qaytaradi. osh uchun zanjir: asosiyTaom, umumiy, Object.prototype — uchta. toString uchinchi qavatda — Object.prototype da.
4-mashq: Vazifalar qadami — nega in emas, Object.hasOwn?
Object.* metodlari darsida filtrniTanla ga himoya qo'shgan edik: filtr nomi boshMatnlar ning o'z kaliti bo'lmasa, funksiya hech narsa qilmaydi. O'shanda "toString" misolida in aldanishini ko'rdik, lekin nega aldanishi ochiq qolgan edi. Bugun javobni bilasiz. Kod allaqachon himoyalangan — bu qadamda uni o'zgartirmaymiz, faqat zanjirni o'z ko'zingiz bilan ko'rasiz va izoh qo'shasiz.
boshMatnlar — oddiy { ... } obyekt (muzlatilgan bo'lsa ham). Demak uning prototipi Object.prototype, unda esa toString, constructor va boshqa o'nta xususiyat bor.
1. Zanjirni ko'ring. Saytni oching va DevTools Console'da yozing:
console.log("constructor" in boshMatnlar);
console.log(Object.hasOwn(boshMatnlar, "constructor"));
console.log(boshMatnlar["constructor"] === Object);Har qator nima chiqaradi va nega?
2. Himoyani sinang. O'sha Console'da vazifalar.js ning global funksiyasini to'g'ridan-to'g'ri chaqiring va filtr tugmalariga, ro'yxatga qarang:
filtrniTanla("constructor");Tekshiruv in bilan yozilganida nima bo'lardi?
3. Savol. Hozir holat.filtr faqat bizning uchta tugmamizdan keladi. Lekin localStorage darsida (11-qism) filtrni saqlab, sahifa ochilganda qayta o'qiymiz — u yerda qiymatni foydalanuvchi o'zgartira oladi. Kirish qiymatiga ishonish mumkinmi?
4. Izoh. Tekshiruv ustiga "nega in emas" degan izoh yozing — kelajakda kimdir uni "soddalashtirib" in ga almashtirmasin.
Yechim
1. Konsolda:
true
false
true"constructor" boshMatnlar ning o'zida yo'q. in esa zanjir bo'ylab qidiradi va uni Object.prototype da topadi. boshMatnlar["constructor"] ham o'sha yo'l bilan Object funksiyasining o'zini qaytaradi. Object.hasOwn faqat obyektning o'ziga qaraydi — false.
2. Hech narsa o'zgarmaydi: «Hammasi» tanlangan holda qoladi, ro'yxat va bo'sh xabar avvalgidek — tekshiruv noma'lum filtrni rad etdi. U in bilan yozilganida, "constructor" undan o'tib ketardi. holat.filtr buzilardi, uchala filtr tugmasi "bosilmagan" bo'lib qolardi, mosmi esa noma'lum filtrga true qaytarib, hamma vazifani ko'rsatardi. Bo'sh ro'yxat xabariga esa function Object() { [native code] } yozilardi — Object.* metodlari darsidagi "toString" tajribasining aynan o'zi.
3. Yo'q. Tashqaridan kelgan har qiymat — localStorage, URL, forma — tekshirilishi kerak. Prototip zanjiri tufayli "bunday kalit yo'q" deb o'ylagan joyingizda kalit bo'lib chiqishi mumkin.
4. Tekshiruv ustidagi izoh (funksiyaning qolgan qismi — avvalgidek):
function filtrniTanla(filtr) {
// Faqat boshMatnlar ning O'Z kalitlari: "constructor",
// "toString" kabi meros kalitlar filtr emas. `in` yaramaydi —
// u prototip zanjiri bo'ylab qidiradi.
if (!Object.hasOwn(boshMatnlar, filtr)) {
// ... (Object.* metodlari darsidagi kod)
}
// ...
}Kod o'zgarmadi, faqat izoh qo'shildi — shuning uchun alohida branch ochmaymiz:
git add assets/js/vazifalar.js
git commit -m "Filtr: hasOwn tekshiruvi sababini izohla"
git pushMaslahat: Kalit tashqaridan keladigan "lug'at"lar uchun yana ikki vosita bor: prototipi umuman yo'q obyekt —
Object.create(null)(Object.create) vaMap(Map). Ikkalasida hamconstructorkabi meros kalitlar yo'q.
10. Real ishda
- Har kuni, sezmasdan.
[].map,"satr".trim(),{}.toString()— har metod chaqiruvi prototip zanjiri bo'ylab qidiruv. Bu darsdan keyin "metod qayerdan keldi?" degan savolga aniq javob bera olasiz. - Klasslar.
classsintaksisi — prototip zanjiri ustidagi qulay yozuv. Klass metodlari aynan prototipga qo'yiladi. Bu bog'lanishniclassichidan darsida ochamiz. - Xavfsizlik. Foydalanuvchi kalitini tekshirmaslik va
__proto__bilan bog'liq xatolar bir necha mashhur kutubxonada jiddiy zaiflikka aylangan. Himoyani Prototype pollution darsida o'rganamiz. - Intervyu. "Prototip zanjiri qanday ishlaydi?", "
__proto__vaprototypefarqi?", "hasOwnvainfarqi?" — o'rta darajadagi JS intervyusining doimiy savollari.
Xulosa
- Har obyektda yashirin
[[Prototype]]havolasi bor — boshqa obyektga yokinullga. UniObject.getPrototypeOf(obj)bilan o'qing. - Xususiyat o'qilganda: avval obyektning o'zi, keyin prototipi, keyin uning prototipi...
nullda —undefined. - Oddiy obyekt →
Object.prototype→null. Massiv →Array.prototype→Object.prototype. Funksiya →Function.prototype→Object.prototype. - Yozish doim obyektning o'ziga tushadi va prototipdagini soyalaydi. Lekin prototipdagi massivga
push— umumiy massivni o'zgartiradi. invafor...in— butun zanjir;Object.hasOwnvaObject.keys— faqat o'zi.- Prototipni yaratishda bering (
Object.create, literal__proto__:).obj.__proto__— eskirgan,setPrototypeOf— sekin.
Keyingi dars: Konstruktor funksiya va new — bir xil tuzilishdagi ko'p obyektni new bilan yasaymiz va metodlarni prototipga qo'yib, ularni bitta nusxada bo'lishamiz.
Manbalar
- MDN: "Inheritance and the prototype chain" — developer.mozilla.org
- MDN: "Object.getPrototypeOf()", "Object.setPrototypeOf()" (ogohlantirish bo'limi), "Object.prototype.proto" (deprecated)
- ECMAScript 2025 Language Specification: "OrdinaryGet", "[[GetPrototypeOf]]" — tc39.es/ecma262
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!