Mundarija (37)
- Bu darsda
- 1. Nega bu kerak?
- 2. Object.create(proto)
- 2.1 Birinchi misol
- 2.2 Object.create ichidan
- 2.3 Ikkinchi argument: deskriptorlar
- 2.4 Object.create yoki new?
- 3. Prototipal meros zanjiri
- 3.1 Uch qavat
- 3.2 Eski kodda: konstruktorlar orasida meros
- 4. Object.create(null): toza lug'at
- 4.1 Muammo: "meros" kalitlar
- 4.2 Yechim: prototipsiz obyekt
- 4.3 Toza lug'atning narxi
- 5. instanceof — zanjirda bormi?
- 5.1 Savol va javob
- 5.2 instanceof ichidan
- 5.3 isPrototypeOf — konstruktorsiz obyektlar uchun
- 5.4 Symbol.hasInstance — savolni o'zgartirish
- 6. DOM'da instanceof va iframe muammosi
- 6.1 li ning oilasi
- 6.2 Ikki oyna — ikki xil Array
- 7. Ko'p uchraydigan xatolar
- 7.1 Ikkinchi argumentdagi "ko'rinmas" xususiyatlar
- 7.2 O'ng tomonda obyekt
- 7.3 Toza lug'atda hasOwnProperty
- 7.4 Prototipni almashtirishdan oldin metod yozish
- 7.5 Massivni instanceof Array bilan tekshirish
- 7.6 Prototipdagi massivni "o'zimniki" deb o'zgartirish
- 8. Mashqlar
- 1-mashq (oson): Taom namunasi
- 2-mashq (o'rta): Teglar sanog'i
- 3-mashq (qiyin): Zanjir uzunligi
- 4-mashq: Vazifalar qadami — vazifa prototipi (mashqlar repo)
- 9. Real ishda
- Xulosa
- Manbalar
JavaScript Object.create: prototipal meros va instanceof
Qisqacha:
Object.create(proto)yangi bo'sh obyekt yaratadi va uning prototipiniprotoqilib qo'yadi — konstruktor ham,newham kerak emas. Prototipsiz "toza lug'at" esaObject.create(null)bilan yaratiladi. Ifodax instanceof F— "F.prototypexning prototip zanjirida bormi?" degan savol; obyektlar uchun xuddi shu savolniproto.isPrototypeOf(x)beradi.
Bu darsda
Object.createbilan istalgan obyektni prototip qilib, yangi obyekt yarata olasiz.- Uch qavatli prototipal meros zanjirini qura olasiz va eski koddagi
Ichimlik.prototype = Object.create(Taom.prototype)qolipini o'qiy olasiz. Object.create(null)lug'ati nega"constructor"kabi kalitlardan qo'rqmasligini tushuntira olasiz.instanceofvaisPrototypeOfzanjirni qanday tekshirishini,Symbol.hasInstanceva iframe bilan bog'liq tuzoqlarni bilasiz.
Oldin bilishingiz kerak: Prototip va prototip zanjiri, Konstruktor funksiya va new, Xususiyat deskriptorlari.
1. Nega bu kerak?
Konstruktor funksiya darsida prototipli obyektni bitta yo'l bilan yaratdik: funksiya yozish, metodlarni Taom.prototype ga qo'yish, so'ng new Taom(...). Bu — ko'p bir xil obyekt kerak bo'lganda qulay.
Lekin ba'zan bitta tayyor obyekt bor va undan "meros oluvchi" yana bitta obyekt kerak. Konstruktor yozish ortiqcha. 08-qismda Obyekt bo'ylab yurish darsida shunday kodni ko'rgan edik:
const buyurtma = Object.create(standart);O'shanda "standart dan meros oluvchi obyekt yaratadi" dedik va tafsilotni shu darsga qoldirdik. Bugun o'sha va'dani bajaramiz.
Prototip zanjiri darsidagi yangi ofitsiantni eslang: u bilmagan savolni Otabekdan, Otabek esa Jasur akadan so'raydi. Ofitsiant hamma narsani yodlamaydi — faqat "kimdan so'rashni" biladi. Object.create aynan shuni qiladi: yangi obyektga "bilmasang, mana bundan so'ra" degan havola beradi. Bu safar "ustoz"ni o'zimiz tanlaymiz.
Darsning ikkinchi yarmida teskari savolni ko'ramiz: obyekt qaysi "oilaga" tegishli? 09-qismda li instanceof HTMLElement ni shunchaki savol sifatida ishlatgan edik. Endi uning ichida nima borligini ochamiz.
2. Object.create(proto)
2.1 Birinchi misol
Menyudagi har taom o'zini bir xil tavsiflaydi. Metodni bitta "namuna" obyektga yozamiz:
const taom = {
tavsifla() {
return `${this.nom}: ${this.narx} so'm`;
},
};
const osh = Object.create(taom);
osh.nom = "Osh";
osh.narx = 35000;
console.log(osh.tavsifla()); // Osh: 35000 so'm
console.log(Object.getPrototypeOf(osh) === taom); // true
console.log(osh); // { nom: 'Osh', narx: 35000 }Uchta narsaga qarang:
oshdatavsiflayo'q — utaomda. JavaScript uni prototip zanjiri bo'ylab topdi.this—osh, chunki metodosh.tavsifla()shaklida chaqirildi (this: to'rt qoida).console.log(osh)faqat o'z xususiyatlarini ko'rsatadi. Prototip konsolda ko'rinmaydi, lekin u bor.
Prototipal meros (prototypal inheritance) — obyekt boshqa obyektning xususiyat va metodlaridan prototip havolasi orqali foydalanishi. Nusxa olinmaydi: osh ichida tavsifla ning nusxasi yo'q, faqat taom ga havola bor.
2.2 Object.create ichidan
HOF darslaridagidek, metodning soddalashtirilgan nusxasini o'zimiz yozamiz. Prototip zanjiri darsidagi Object.setPrototypeOf bilan:
function yarat(proto) {
const yangi = {};
Object.setPrototypeOf(yangi, proto);
return yangi;
}
const taom = { turi: "taom" };
const manti = yarat(taom);
console.log(manti.turi); // taom
console.log(Object.getPrototypeOf(manti) === taom); // trueUch qadam: bo'sh obyekt, prototipni ulash, qaytarish. new ning to'rt qadamidan (Konstruktor funksiya va new) farqi — bu yerda hech qanday funksiya chaqirilmaydi. Shuning uchun this.nom = nom kabi tayyorlash ham yo'q: xususiyatlarni keyin o'zingiz yozasiz.
Haqiqiy Object.create buni bitta amal bilan qiladi va tezroq. Obyekt yaratilgandan keyin prototipni almashtirish (setPrototypeOf) JavaScript dvigatellarida sekin ishlaydi. MDN ham shuni ogohlantiradi. Shuning uchun real kodda yarat emas, Object.create yoziladi.
2.3 Ikkinchi argument: deskriptorlar
Object.create ikkinchi argument ham oladi — xususiyat deskriptorlari, Object.defineProperties dagidek:
const taom = {
tavsifla() {
return `${this.nom}: ${this.narx} so'm`;
},
};
const manti = Object.create(taom, {
nom: { value: "Manti" },
narx: { value: 30000 },
});
console.log(manti.tavsifla()); // Manti: 30000 so'm
console.log(manti); // {}Metod ishladi, lekin console.log bo'sh {} ko'rsatdi! Deskriptorda yozilmagan bayroqlar false bo'ladi: xususiyatlar sanalmaydi (enumerable: false), o'zgarmaydi (writable: false).
manti.narx = 32000 deb yozsangiz, strict rejimda (modulda ham, saytdagi «Ishga tushir» da ham) xato chiqadi: TypeError: Cannot assign to read only property 'narx' of object '#<Object>' — "faqat o'qiladigan narx xususiyatiga qiymat berib bo'lmaydi". Eski uslubdagi skriptda esa tayinlash jimgina e'tiborsiz qoladi.
Shuning uchun ikkinchi argument kamdan-kam ishlatiladi. Oddiy yo'l — yaratib, keyin tayinlash yoki Object.assign bilan:
const taom = { turi: "taom" };
const manti = Object.assign(Object.create(taom), {
nom: "Manti",
narx: 30000,
});
console.log(manti); // { nom: 'Manti', narx: 30000 }
console.log(manti.turi); // taomO'zingiz to'ldiring. Object.getPrototypeOf(Object.create(taom)) === taom natijasi — .
Tekshirib ko'ring:
const a = { x: 1 }; const b = Object.create(a); a.x = 5;—b.xnimaga teng?
Javob
5. b da o'z x i yo'q, u har safar a dan so'raydi. a.x o'zgardi — b.x ham yangisini ko'rsatadi. Prototip — nusxa emas, jonli havola. Ofitsiant misolida: ustoz narxni yangilasa, shogird ertasiga yangi narxni aytadi.
2.4 Object.create yoki new?
Ikkalasi ham prototipli obyekt beradi. Farqi — "qolip" bormi-yo'qligida:
| Savol | Object.create(proto) |
new F(...) |
|---|---|---|
| Prototip qayerdan? | Siz bergan istalgan obyekt | Har doim F.prototype |
| Tayyorlash kodi | Yo'q, xususiyatni keyin yozasiz | F ning tanasi ishlaydi |
| Qachon qulay | Bitta-ikkita obyekt, tayyor namuna bor | Ko'p bir xil obyekt |
Masalan, «Bahor» buyurtmasining sukut bo'yicha sozlamalari bitta obyektda turadi: valyuta, xizmat haqi foizi, stol raqami. Har yangi buyurtma ularni "ko'radi", lekin o'zgartirsa — o'zida o'zgartiradi:
const standart = { valyuta: "so'm", xizmatFoizi: 10 };
const buyurtma = Object.create(standart);
buyurtma.xizmatFoizi = 0; // bayramda xizmat haqi yo'q
console.log(buyurtma.valyuta, buyurtma.xizmatFoizi); // so'm 0
console.log(standart.xizmatFoizi); // 10buyurtma.xizmatFoizi = 0 prototipdagi qiymatni o'zgartirmadi — buyurtma ning o'zida yangi xususiyat yaratdi va u prototipdagisini soyaladi. standart joyida qoldi. Yozish doim obyektning o'ziga tushadi, o'qish esa zanjir bo'ylab qidiradi. Shu ikki qoida prototipal merosning butun mexanikasi.
08-qismdagi Obyekt bo'ylab yurish darsidagi natija ham endi tushunarli. for...in zanjirdagi sanaladigan kalitlarni ham beradi, shuning uchun valyuta ro'yxatga tushgan edi. Object.keys esa faqat o'z kalitlarini beradi. Prototipdan kelgan sozlamani "o'zimniki" deb yuborib qo'ymaslik uchun real kodda ko'pincha Object.keys yoki Object.entries ishlatiladi.
Tekshirib ko'ring: Yuqoridagi koddan keyin
delete buyurtma.xizmatFoiziqilinsa,buyurtma.xizmatFoizinimaga teng bo'ladi?
Javob
10. delete faqat obyektning o'z xususiyatini o'chiradi. O'zida xizmatFoizi qolmadi — o'qish yana zanjirga chiqadi va standart dagi 10 ni topadi. Prototipdagi qiymatni buyurtma orqali o'chirib bo'lmaydi.
3. Prototipal meros zanjiri
3.1 Uch qavat
Ichimlik — taomning bir turi, ko'k choy — ichimlikning bir turi. Har qavat yuqoridagidan meros oladi va o'zinikini qo'shadi:
const taom = {
tavsifla() {
return `${this.nom}: ${this.narx} so'm`;
},
};
const ichimlik = Object.create(taom);
ichimlik.tavsifla = function () {
return `${this.nom} (${this.hajm}): ${this.narx} so'm`;
};
const choy = Object.create(ichimlik);
choy.nom = "Ko'k choy";
choy.narx = 5000;
choy.hajm = "choynak";
console.log(choy.tavsifla()); // Ko'k choy (choynak): 5000 so'mchoy.tavsifla qidirilganda JavaScript avval choy ning o'ziga qaraydi — yo'q. Keyin ichimlik ga — bor, to'xtaydi. taom dagi tavsifla gacha yetib bormaydi: ichimlik dagisi uni soyalaydi (shadowing). Zanjir shunday ko'rinadi:
flowchart LR
C["choy<br/>nom, narx, hajm"] --> I["ichimlik<br/>tavsifla"]
I --> T["taom<br/>tavsifla"]
T --> O["Object.prototype<br/>toString, hasOwnProperty"]
O --> N["null"]O'qlar — prototip havolasi. Qidiruv chapdan o'ngga yuradi va birinchi topilgan joyda to'xtaydi. null ga yetib, hech narsa topilmasa — undefined.
3.2 Eski kodda: konstruktorlar orasida meros
class paydo bo'lishidan oldin (2015-yilgacha) ikki konstruktor orasidagi merosni Object.create bilan qo'lda qurishardi. Bu kod hali ham ko'p kutubxonada bor:
function Taom(nom, narx) {
this.nom = nom;
this.narx = narx;
}
Taom.prototype.tavsifla = function () {
return `${this.nom}: ${this.narx} so'm`;
};
function Ichimlik(nom, narx, hajm) {
Taom.call(this, nom, narx); // 1
this.hajm = hajm;
}
Ichimlik.prototype = Object.create(Taom.prototype); // 2
Ichimlik.prototype.constructor = Ichimlik; // 3
const choy = new Ichimlik("Ko'k choy", 5000, "choynak");
console.log(choy.tavsifla()); // Ko'k choy: 5000 so'm
console.log(choy.constructor.name); // IchimlikUch belgilangan qator:
Taom.call(this, ...)— ota konstruktorni yangi obyekt ustida ishga tushiradi (call,apply,bind).nomvanarxshu tufayli yoziladi.Ichimlik.prototype—Taom.prototypedan meros oluvchi yangi obyekt. Endichoy→Ichimlik.prototype→Taom.prototypezanjiri bor.- 2-qator eski
Ichimlik.prototypeni almashtirdi va u bilan birgaconstructorxususiyati ham yo'qoldi. Uni qo'lda tiklaymiz, aks holdachoy.constructorTaomni ko'rsatadi.
Bu qolipni o'zingiz yozishingiz shart emas. Meros: extends va super darsida xuddi shu ishni class Ichimlik extends Taom bitta qatorda qiladi — ichida esa aynan shu zanjir quriladi. Hozir uni eski kodda tanib olsangiz yetarli.
Tekshirib ko'ring: 2-qatorni
Ichimlik.prototype = Taom.prototypedeb yozsak nima bo'ladi?
Javob
Ikkala konstruktor bitta prototip obyektini ishlatib qoladi. Ichimlik uchun Ichimlik.prototype.tavsifla = ... deb metod yozsangiz, u Taom.prototype ga ham yoziladi — endi osh ham "choynak" haqida gapiradi. Object.create esa ichimliklar uchun alohida obyekt yaratadi, u faqat Taom.prototype ga havola qiladi.
4. Object.create(null): toza lug'at
4.1 Muammo: "meros" kalitlar
Telegram bot mehmonlar yozgan teglarni sanaydi. reduce darsidagi sanoq qolipi, oddiy {} bilan:
const teglar = ["osh", "constructor", "osh", "toString"];
const sanoq = {};
for (const teg of teglar) {
sanoq[teg] = (sanoq[teg] ?? 0) + 1;
}
console.log(sanoq.osh);
console.log(sanoq.constructor);
console.log(sanoq.toString);Konsolda:
2
function Object() { [native code] }1
function toString() { [native code] }1"osh" to'g'ri sanaldi, qolgan ikkitasi — g'alati satr. Sabab: {} ning prototipi Object.prototype, unda esa constructor va toString allaqachon bor. sanoq["constructor"] birinchi marta undefined emas, funksiya qaytardi. ?? 0 ishlamadi, funksiya + 1 esa satrga aylandi (Yashirin coercion).
Kalitni foydalanuvchi yozsa — u istalgan narsa bo'lishi mumkin. 08-qismda Obyekt: kalit-qiymat juftliklari darsida in operatori shu sabab bilan "toString" ni "bor" deganini ko'rgan edik.
4.2 Yechim: prototipsiz obyekt
Object.create(null) — prototipi null bo'lgan obyekt. Unda hech qanday meros xususiyat yo'q:
const teglar = ["osh", "constructor", "osh", "toString"];
const sanoq = Object.create(null);
for (const teg of teglar) {
sanoq[teg] = (sanoq[teg] ?? 0) + 1;
}
console.log(sanoq);
console.log(Object.getPrototypeOf(sanoq)); // nullKonsolda:
[Object: null prototype] { osh: 2, constructor: 1, toString: 1 }
nullNode bunday obyektni [Object: null prototype] deb belgilaydi — "bu oddiy obyekt emas, prototipi yo'q". Endi har kalit — faqat bizning ma'lumot.
4.3 Toza lug'atning narxi
Prototip yo'q — demak Object.prototype dagi qulayliklar ham yo'q:
sanoq.hasOwnProperty("osh")—TypeError: sanoq.hasOwnProperty is not a function. O'rnigaObject.hasOwn(sanoq, "osh")— u obyektning o'z metodiga tayanmaydi.`${sanoq}`yokiString(sanoq)—TypeError: Cannot convert object to primitive value: satrga aylantiradigantoStringyo'q.sanoq instanceof Object—false. Nega — keyingi bo'limda ko'ramiz.
Shuning uchun toza lug'atni faqat kalitlari tashqaridan keladigan joyda ishlating: foydalanuvchi teglari, so'zlar sanog'i, URL parametrlari. Bunday ish uchun maxsus to'plam ham bor — Map, uni Map darsida o'rganamiz. Object.create(null) esa oddiy obyekt sintaksisi kerak bo'lgan joyda qoladi. Bu mavzu xavfsizlikka ham bevosita bog'liq — Prototype pollution darsida ko'ramiz.
Tekshirib ko'ring:
const l = Object.create(null); l.osh = 1;—"osh" in lva"toString" in lnima qaytaradi?
Javob
true va false. in zanjirni ham tekshiradi, lekin l da zanjir yo'q — faqat o'z kalitlari bor. Oddiy {} da esa "toString" in {} — true.
5. instanceof — zanjirda bormi?
5.1 Savol va javob
instanceof chap tomondagi obyekt o'ng tomondagi konstruktorning "oilasiga" kirishini so'raydi. «Eski kodda» bo'limidagi merosda:
function Taom(nom) {
this.nom = nom;
}
function Ichimlik(nom) {
Taom.call(this, nom);
}
Ichimlik.prototype = Object.create(Taom.prototype);
const choy = new Ichimlik("Ko'k choy");
const osh = new Taom("Osh");
console.log(choy instanceof Ichimlik, choy instanceof Taom);
console.log(osh instanceof Ichimlik, osh instanceof Object);Konsolda:
true true
false truechoy ham Ichimlik, ham Taom — meros bo'ylab. osh esa faqat Taom (va Object — deyarli hamma obyekt shunday).
5.2 instanceof ichidan
instanceof nomga yoki konstruktor funksiyaning o'ziga qaramaydi. U bitta narsani qidiradi: F.prototype obyektini chap tomondagi obyektning zanjirida. O'zimiz yozamiz:
function nusxasimi(obyekt, Konstruktor) {
let joriy = Object.getPrototypeOf(obyekt);
while (joriy !== null) {
if (joriy === Konstruktor.prototype) {
return true;
}
joriy = Object.getPrototypeOf(joriy);
}
return false;
}
console.log(nusxasimi([], Array), nusxasimi([], Object)); // true true
console.log(nusxasimi({}, Array)); // falseQadamma-qadam, choy instanceof Taom uchun. Keyingi tugmasini bosib, joriy zanjir bo'ylab qanday yurishiga qarang:
Bundan uchta xulosa chiqadi:
instanceof— hozirgi zanjir haqidagi savol.F.prototypekeyin boshqa obyektga almashtirilsa, oldin yaratilgan obyektlar uchun javobfalsebo'lib qoladi.Object.create(null)dan yaratilgan obyektning zanjiri bo'sh —instanceof Objecthamfalse.- O'ng tomon — funksiya bo'lishi shart. Oddiy obyekt bersangiz:
TypeError: Right-hand side of 'instanceof' is not callable("instanceofning o'ng tomoni chaqirib bo'ladigan narsa emas").
5.3 isPrototypeOf — konstruktorsiz obyektlar uchun
Yuqoridagi taom, ichimlik, choy — konstruktorsiz, oddiy obyektlar. choy instanceof taom xato beradi. Ular uchun teskari tomondan so'raladi:
const taom = {};
const ichimlik = Object.create(taom);
const choy = Object.create(ichimlik);
console.log(taom.isPrototypeOf(choy)); // true
console.log(choy.isPrototypeOf(taom)); // false
console.log(Object.prototype.isPrototypeOf(choy)); // truea.isPrototypeOf(b) — "a b ning zanjirida bormi?" Bu instanceof ning o'zi, faqat konstruktor o'rniga to'g'ridan-to'g'ri obyekt beriladi: x instanceof F ≈ F.prototype.isPrototypeOf(x).
Qaysi birini tanlash oddiy. Qo'lingizda konstruktor (keyinroq — klass) bo'lsa, instanceof o'qishga qulayroq: "choy — ichimlikmi?". Qo'lingizda faqat namuna obyekt bo'lsa — isPrototypeOf. Ikkalasi ham zanjirning istalgan qavatini topadi, faqat birinchi qavatni emas. Faqat bevosita prototipni tekshirish kerak bo'lsa — Object.getPrototypeOf(x) === proto.
5.4 Symbol.hasInstance — savolni o'zgartirish
instanceof ning javobini o'zgartirish ham mumkin. O'ng tomondagi obyektda Symbol.hasInstance nomli metod bo'lsa, JavaScript zanjirga qaramaydi — shu metodni chaqiradi. Symbol — kalit sifatida ishlatiladigan maxsus noyob qiymat turi; uni Symbol darsida o'rganamiz, hozir bilish shart emas:
const Juft = {
[Symbol.hasInstance](son) {
return son % 2 === 0;
},
};
console.log(4 instanceof Juft, 7 instanceof Juft); // true falseQiziq, lekin real kodda kam uchraydi: instanceof dan "oila" savolini kutgan odam bunday javobdan adashadi. Uni bilishingiz uchun bir sabab bor — instanceof ni aldash mumkin. Shuning uchun xavfsizlik uchun muhim tekshiruvni faqat unga tayantirmang. Ishonchliroq usulni Private # maydon darsida ko'ramiz.
6. DOM'da instanceof va iframe muammosi
6.1 li ning oilasi
09-qismda DOM daraxti darsida li instanceof HTMLElement ni savol sifatida ishlatgan edik. Endi uning nega true ekanini ko'ramiz — zanjirni yuqoriga yuramiz:
<ul>
<li>Osh</li>
</ul>
<script>
const li = document.querySelector("li");
const nomlar = [];
let joriy = Object.getPrototypeOf(li);
while (joriy !== null) {
nomlar.push(joriy.constructor.name);
joriy = Object.getPrototypeOf(joriy);
}
console.log(nomlar.join(" → "));
const quti = document.createDocumentFragment();
console.log(quti instanceof DocumentFragment, quti instanceof Node);
</script>Konsolda:
HTMLLIElement → HTMLElement → Element → Node → EventTarget → Object
true trueHar zanjir qadami — bitta prototip obyekti, uning constructor i esa "oila" nomini beradi. Savol li instanceof Element — true, chunki Element.prototype shu zanjirda bor. Ko'p elementni samarali chizish darsidagi document.createDocumentFragment() va new DocumentFragment() ning natijasi bir xil ekani ham shundan: ikkalasi ham DocumentFragment.prototype ga ulangan obyekt beradi.
6.2 Ikki oyna — ikki xil Array
Har brauzer oynasi va har iframe ning o'z global obyektlari bor: o'z Array, o'z Object, o'z Array.prototype. Bunday alohida dunyo realm deyiladi (inglizcha "qirollik, olam"). Bir realm'da yaratilgan massiv boshqa realm'ning Array.prototype iga ulanmagan:
const ramka = document.createElement("iframe");
document.body.append(ramka);
const BoshqaArray = ramka.contentWindow.Array;
const taomlar = BoshqaArray.of("osh", "manti");
console.log(taomlar instanceof Array); // false
console.log(Array.isArray(taomlar)); // true
console.log(BoshqaArray === Array); // falseBu kodni istalgan sahifada DevTools konsoliga yozib sinang. Saytdagi natija oynasi xavfsizlik uchun yopiq "qum quti"da ishlaydi va ichki ramkaga kirishni to'sadi — shuning uchun bu misol natija emas, konsol uchun.
taomlar — haqiqiy massiv, lekin instanceof Array "yo'q" deydi: u boshqa Array.prototype ga ulangan. Array.isArray esa zanjirga emas, obyektning ichki turiga qaraydi — u realm'dan qat'i nazar to'g'ri javob beradi.
Nega ikki xil savol ikki xil javob beradi? Massiv bo'lish — obyekt yaratilganda dvigatel qo'ygan ichki belgi, u hech qachon o'zgarmaydi. Prototip esa oddiy havola: uni almashtirish, null qilish, boshqa oynanikiga ulash mumkin. instanceof havolani tekshiradi, Array.isArray — belgini. Bu farq faqat massivga tegishli emas: iframe'dan kelgan Date yoki Error ham instanceof Date da false beradi.
Qoida: massivni tekshirishda doim Array.isArray. instanceof ni o'z kodingizda yaratilgan obyektlar uchun ishlating. Realm muammosi iframe, brauzer kengaytmalari va Node'dagi vm modulida uchraydi.
Tekshirib ko'ring:
structuredClonebilan nusxalangannew Taom("Osh")uchunnusxa instanceof Taomnima qaytaradi?
Javob
false. structuredClone faqat ma'lumotni nusxalaydi: nusxa — prototipi Object.prototype bo'lgan oddiy obyekt. nom bor, tavsifla yo'q. JSON.parse(JSON.stringify(...)) da ham xuddi shunday. Ma'lumot bir joydan ikkinchisiga "safar qilsa", prototip yo'lda qoladi.
7. Ko'p uchraydigan xatolar
7.1 Ikkinchi argumentdagi "ko'rinmas" xususiyatlar
Object.create(proto, { nom: { value: "Manti" } }) — console.log {} ko'rsatadi, Object.keys bo'sh, tayinlash ishlamaydi. Deskriptor bayroqlari sukut bo'yicha false. Tuzatish: yaratib, keyin oddiy tayinlash yoki Object.assign(Object.create(proto), {...}).
7.2 O'ng tomonda obyekt
const taom = {};
const osh = Object.create(taom);
console.log(osh instanceof taom);TypeError: Right-hand side of 'instanceof' is not callableTarjimasi: "instanceof ning o'ng tomoni chaqirib bo'ladigan narsa emas". instanceof konstruktor funksiyani kutadi, taom esa oddiy obyekt. Tuzatish: taom.isPrototypeOf(osh).
7.3 Toza lug'atda hasOwnProperty
const sanoq = Object.create(null);
sanoq.osh = 2;
console.log(sanoq.hasOwnProperty("osh"));TypeError: sanoq.hasOwnProperty is not a functionTarjimasi: "sanoq.hasOwnProperty funksiya emas". Bu metod Object.prototype da yashaydi, toza lug'atda esa prototip yo'q — sanoq.hasOwnProperty undefined bo'ldi va uni chaqirib bo'lmadi. Tuzatish: Object.hasOwn(sanoq, "osh") — har qanday obyekt bilan ishlaydi.
7.4 Prototipni almashtirishdan oldin metod yozish
Eski merosda tartib muhim:
Ichimlik.prototype.hajmniAyt = function () { /* ... */ };
// ❌ metod yo'qoldi:
Ichimlik.prototype = Object.create(Taom.prototype);Ikkinchi qator butun prototip obyektini almashtiradi — oldin yozilgan hajmniAyt eski obyekt bilan birga ketadi. Tuzatish: avval Object.create, keyin metodlar.
7.5 Massivni instanceof Array bilan tekshirish
Iframe yoki boshqa realm'dan kelgan massivda false. Tuzatish: Array.isArray(x).
7.6 Prototipdagi massivni "o'zimniki" deb o'zgartirish
«Yozish doim obyektning o'ziga tushadi» qoidasining bitta istisnoga o'xshash joyi bor:
const standart = { izohlar: [] };
const birinchi = Object.create(standart);
const ikkinchi = Object.create(standart);
birinchi.izohlar.push("achchiq bo'lmasin");
console.log(ikkinchi.izohlar); // [ "achchiq bo'lmasin" ]Ikkinchi buyurtmaga birinchisining izohi tushib qoldi! Bu — Prototip zanjiri darsidagi tanish tuzoq: push — yozish emas, o'qish. O'qish zanjirdan standart dagi yagona massivni topdi va push uning ichini o'zgartirdi. Object.create bilan ham u xuddi shunday kelib chiqadi.
Tuzatish: o'zgaradigan massiv va obyektlarni har obyektning o'ziga qo'ying: birinchi.izohlar = []. Prototipda faqat metodlar va o'zgarmaydigan sukut qiymatlari tursin. Klasslarda bu qoida yanada muhim — Class maydonlari darsida ko'ramiz.
8. Mashqlar
1-mashq (oson): Taom namunasi
taom namunasidan Object.create bilan lagmon obyektini yarating (nom — "Lag'mon", narx — 28000) va lagmon.tavsifla() natijasini chiqaring. So'ng Object.hasOwn bilan tavsifla lagmon ning o'zida emasligini ko'rsating.
const taom = {
tavsifla() {
return `${this.nom}: ${this.narx} so'm`;
},
};Yechim
const taom = {
tavsifla() {
return `${this.nom}: ${this.narx} so'm`;
},
};
const lagmon = Object.create(taom);
lagmon.nom = "Lag'mon";
lagmon.narx = 28000;
console.log(lagmon.tavsifla()); // Lag'mon: 28000 so'm
console.log(Object.hasOwn(lagmon, "tavsifla")); // false
console.log(Object.hasOwn(taom, "tavsifla")); // trueMetod taom da yashaydi, lagmon faqat unga havola qiladi.
2-mashq (o'rta): Teglar sanog'i
teglarniSana(teglar) funksiyasini yozing. U toza lug'at qaytarsin. So'ng "__proto__" tegini ham bering — u ham oddiy kalit sifatida sanalsinmi? Tekshiring.
Ishora: sanoq qolipi — «Toza lug'at» bo'limida; Object.create(null).
Yechim
function teglarniSana(teglar) {
const sanoq = Object.create(null);
for (const teg of teglar) {
sanoq[teg] = (sanoq[teg] ?? 0) + 1;
}
return sanoq;
}
const natija = teglarniSana(["osh", "__proto__", "osh"]);
console.log(Object.keys(natija)); // [ 'osh', '__proto__' ]
console.log(natija.__proto__); // 1Ha, sanaldi. Oddiy {} da __proto__ — Object.prototype dagi maxsus xususiyat: unga yozish prototipni almashtirishga urinadi. Toza lug'atda Object.prototype yo'q, demak maxsus xususiyat ham yo'q — __proto__ oddiy kalitga aylanadi. Bu farq keyingi darsdan keyingi Prototype pollution darsining markazida turadi.
3-mashq (qiyin): Zanjir uzunligi
zanjirUzunligi(obyekt) funksiyasini yozing: obyektdan null gacha nechta prototip borligini qaytarsin. {}, [], Object.create(null) va «Uch qavat» bo'limidagi choy uchun sinang.
Yechim
function zanjirUzunligi(obyekt) {
let soni = 0;
let joriy = Object.getPrototypeOf(obyekt);
while (joriy !== null) {
soni++;
joriy = Object.getPrototypeOf(joriy);
}
return soni;
}
const taom = {};
const ichimlik = Object.create(taom);
const choy = Object.create(ichimlik);
console.log(zanjirUzunligi({})); // 1
console.log(zanjirUzunligi([])); // 2
console.log(zanjirUzunligi(Object.create(null))); // 0
console.log(zanjirUzunligi(choy)); // 3{} → Object.prototype (1). [] → Array.prototype → Object.prototype (2). choy → ichimlik → taom → Object.prototype (3). Sikl — nusxasimi bilan bir xil, faqat solishtirish o'rniga sanaydi.
4-mashq: Vazifalar qadami — vazifa prototipi (mashqlar repo)
Bu dars mavzusi vazifalar ilovasini o'zgartirishni talab qilmaydi — qadam mashqlar repoda: kurs/mashqlar/10/33-object-create/vazifa.js. Lekin u ilovaning keyingi qadamiga tayyorgarlik.
vazifalar da har vazifa — oddiy obyekt, uni o'zgartiradigan kod esa tashqarida: vazifaniAlmashtir va vazifaniYangila funksiyalarida. Bu mashqda "belgilash" xulqini vazifaning o'ziga — prototipga — ko'chirib ko'ring:
vazifaProtoobyekti —almashtir()metodi bilan (bajarildini teskarisiga o'zgartiradi).vazifaYarat(id, matn)—Object.create(vazifaProto)bilan yangi vazifa qaytaradi (bajarildi: false).- Ikki vazifa yarating, bittasini
almashtir()qiling va natijani chiqaring.
Yechim
const vazifaProto = {
almashtir() {
this.bajarildi = !this.bajarildi;
},
};
function vazifaYarat(id, matn) {
const vazifa = Object.create(vazifaProto);
vazifa.id = id;
vazifa.matn = matn;
vazifa.bajarildi = false;
return vazifa;
}
const non = vazifaYarat(1, "Non olish");
const qongiroq = vazifaYarat(2, "Onamga qo'ng'iroq qilish");
non.almashtir();
console.log(non); // { id: 1, matn: 'Non olish', bajarildi: true }
console.log(qongiroq.bajarildi); // false
console.log(non.almashtir === qongiroq.almashtir); // trueOxirgi qator — asosiy foyda: ming vazifada ham almashtir bitta, hammasi uni prototipdan oladi. Funksiya vazifaYarat esa "qolip" vazifasini bajaryapti. class sintaksisi darsida aynan shu ikki qismni — qolip va umumiy metodlarni — bitta class Vazifa bloki bilan yozamiz va ilovaning o'ziga qo'shamiz.
Commit (mashqlar repo): 10/33: vazifa prototipini Object.create bilan yasa.
9. Real ishda
- Lug'at va kesh. Foydalanuvchi kalitlari bilan ishlaydigan kodda
Object.create(null)keng tarqalgan. Masalan, Node.js'ningquerystring.parsefunksiyasi natijani shunday obyekt sifatida qaytaradi —constructornomli parametr ham xavfsiz. - Eski kutubxonalar.
Child.prototype = Object.create(Parent.prototype)— 2010-yillardagi kodda, Node.js'ning eski modullarida, jQuery plaginlarida tez-tez uchraydi. Kodni o'qiyotganda "bu — klass merosining qo'lda yozilgani" deb tanib oling. - Sozlamalar zanjiri. Ko'p vositalarda sozlama qatlamlardan yig'iladi: dastur sukuti → loyiha fayli → foydalanuvchi tanlovi. Prototip zanjiri aynan shunday "yuqoridan so'ra" qatlamlari; ba'zi kutubxonalar (masalan, shablon tizimlari) kontekstni shu usulda
Object.create(ota)bilan quradi — ichki qatlam tashqi qatlamdagi o'zgaruvchilarni ko'radi, o'zinikini qo'shsa, tashqarisi buzilmaydi. - Tur tekshiruvi.
error instanceof TypeError,element instanceof HTMLInputElement— xato va DOM bilan ishlashda har kuni. Massiv uchun esa doimArray.isArray. - Intervyu. "
instanceofqanday ishlaydi?", "Object.create(null)nima uchun kerak?", "Object.createvanewfarqi?" — prototip bo'yicha klassik savollar. Bugun uchalasining javobini ichidan bilasiz.
Xulosa
Object.create(proto)— bo'sh obyekt yaratib, prototipiniprotoqiladi; konstruktor chaqirilmaydi.- Prototip — nusxa emas, jonli havola: prototip o'zgarsa, merosxo'rlar darhol yangisini ko'radi.
Object.create(null)— meros kalitlarsiz toza lug'at; tekshirish uchunObject.hasOwn.x instanceof F—F.prototypexning zanjirida bormi; obyektlar uchun —proto.isPrototypeOf(x).instanceofniSymbol.hasInstanceo'zgartira oladi, realm'lar orasida esa u adashadi — massivgaArray.isArray.
Keyingi dars: O'rnatilgan prototiplar va wrapper obyektlar — "Toshkent".length qanday ishlashini va Array.prototype ga o'z metodingizni qo'shish nega xavfli ekanini ko'ramiz.
Manbalar
- MDN: "Object.create()", "instanceof", "Object.prototype.isPrototypeOf()", "Symbol.hasInstance", "Inheritance and the prototype chain" — developer.mozilla.org
- ECMAScript 2025 Language Specification: "OrdinaryHasInstance", "Object.create" — tc39.es/ecma262
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!