Object.create
Object.create nima qiladi, new'dan farqi, Object.create(null), ikkinchi argument (descriptor), toza inheritance va Object.setPrototypeOf bilan performance solishtiruvi.
31-dars
Object.create
1. Object.create nima qiladi — asosiy g'oya
const animal = {
eat() {
return `${this.name} yeyapti`;
}
};
const dog = Object.create(animal);
dog.name = 'Rex';
console.log(dog.eat()); // 'Rex yeyapti'
Object.create(proto) — yangi, bo'sh obyekt yaratadi, va uning [[Prototype]]ini to'g'ridan-to'g'ri, aniq siz ko'rsatgan protoga ulaydi. Bu — eng toza, to'g'ridan-to'g'ri prototype bog'lash usuli — new yoki constructor function orqali "aylanma yo'l" bosmasdan.
HEAP:
dog {}
[[Prototype]] ──→ animal { eat }
2. Object.create vs new — farqi
newning 4 qadamini eslang:
new Fn(args):
1. newObj = {}
2. newObj.[[Prototype]] = Fn.prototype
3. Fn.call(newObj, args) ← FUNKSIYA TANASI BAJARILADI!
4. return tekshirish
Object.create(proto) esa — faqat 1 va 2-qadamni bajaradi:
Object.create(proto):
1. newObj = {}
2. newObj.[[Prototype]] = proto
(VASSALOM — funksiya chaqirilmaydi, chunki proto FUNKSIYA EMAS, oddiy obyekt!)
Bu — eng muhim farq: new — bu constructor function chaqirish + prototype bog'lash birgalikda. Object.create — bu faqat prototype bog'lash, hech qanday constructor logikasi ishga tushmaydi.
function Animal(name) {
this.name = name; // Bu kod 'Object.create' orqali HECH QACHON ishga tushmaydi!
}
const a1 = Object.create(Animal.prototype); // faqat prototype ulandi
console.log(a1.name); // undefined — constructor tanasi chaqirilmagani uchun!
const a2 = new Animal('Rex'); // constructor CHAQIRILDI
console.log(a2.name); // 'Rex'
3. Object.create(null) — zanjirsiz obyekt
const pureObj = Object.create(null);
console.log(pureObj.toString); // undefined — Object.prototype ham yo'q!
Object.create(null) — bu zanjirsiz, "sof" obyekt yaratadi. Bu — Object.createning eng ko'p ishlatiladigan amaliy holatlaridan biri: xavfsiz dictionary/hash-map yasash uchun (prototype pollution xavfisiz).
4. Ikkinchi argument — property descriptor bilan birga yaratish
Object.createning 2-argumenti bor:
const dog = Object.create(animal, {
name: {
value: 'Rex',
writable: true,
enumerable: true,
configurable: true
},
breed: {
value: 'Labrador',
writable: false, // O'ZGARTIRIB BO'LMAYDI
enumerable: true,
configurable: false
}
});
console.log(dog.name); // 'Rex'
console.log(dog.breed); // 'Labrador'
dog.breed = 'Boshqa'; // sokin ignore qilinadi (writable: false)
console.log(dog.breed); // 'Labrador' — o'zgarmadi
Muhim eslatma: bu ikkinchi argumentdagi descriptor'larning default qiymatlari — falsedan boshlanadi (xuddi Object.definePropertydagi kabi) — agar aniq ko'rsatmasangiz, writable, enumerable, configurable — barchasi false bo'lib qoladi.
const obj = Object.create({}, {
x: { value: 10 } // writable/enumerable/configurable YOZILMAGAN
});
console.log(Object.keys(obj)); // [] — 'x' KO'RINMAYDI! (enumerable: false, default)
obj.x = 20; // ISHLAMAYDI (writable: false, default)
console.log(obj.x); // 10 — o'zgarmadi
5. Klassik meros olishning "toza" usuli — Object.create bilan
Dog.prototype = Object.create(Animal.prototype);
Nega aynan Object.create(Animal.prototype), nima uchun new Animal() emas?
// ❌ YOMON YO'L — ba'zan ishlatiladi, lekin muammoli:
Dog.prototype = new Animal(); // Animal CONSTRUCTOR chaqiriladi!
// ✅ TO'G'RI YO'L:
Dog.prototype = Object.create(Animal.prototype); // faqat PROTOTYPE ulanadi
Nega new Animal() yomon? Chunki bu — Animalning constructor tanasini ishga tushiradi (masalan, agar Animal konstruktorida this.name = name bo'lsa, lekin name argument berilmagan bo'lsa — undefined qiymat bilan keraksiz property yaratiladi, va bundan tashqari agar constructor'da side-effect — masalan tarmoq so'rovi yoki log yozish — bo'lsa, bu keraksiz joyda ishga tushib qoladi):
function Animal(name) {
this.name = name;
console.log('Animal yaratildi!'); // SIDE EFFECT
}
Dog.prototype = new Animal(); // "Animal yaratildi!" KONSOLGA CHIQADI — kerak emas edi!
// Bundan tashqari, Dog.prototype endi 'name: undefined' degan KERAKSIZ property'ga ega
Object.create(Animal.prototype) esa — hech qanday constructor logikasi ishlatmasdan, faqat zanjirni ulaydi — bu aynan kerak bo'lgan narsa, ortiqcha side-effect yo'q.
6. Object.create — Object.setPrototypeOf bilan solishtirish
// Variant A: Object.create — YARATISH bilan bir vaqtda
const dog = Object.create(animal);
// Variant B: Object.setPrototypeOf — MAVJUD obyektning prototype'ini O'ZGARTIRISH
const dog2 = {};
Object.setPrototypeOf(dog2, animal);
Natija ikkalasida ham bir xil ko'rinadi, lekin performance jihatdan katta farq bor:
// ❌ SEKIN — Hidden Class allaqachon C0 {} bo'lib shakllangan,
// keyin uni MAJBURAN o'zgartirish V8 uchun QIMMAT operatsiya
// (V8 bu obyektga tegishli barcha Inline Cache'larni BEKOR QILISHI kerak)
const obj1 = {};
Object.setPrototypeOf(obj1, someProto);
// ✅ TEZ — Hidden Class BOSHIDANOQ to'g'ri prototype bilan yaratiladi
const obj2 = Object.create(someProto);
Sabab: Object.create — obyekt hali yaratilmasdan, Hidden Class'ni to'g'ridan-to'g'ri kerakli prototype bilan shakllantiradi. Object.setPrototypeOf esa — allaqachon mavjud obyektning fundamental xususiyatini (prototype'ini) o'zgartiradi, bu V8 uchun juda kamdan-kam, "megamorphic" operatsiya hisoblanadi va katta performance narxiga ega (chunki bu obyektga bog'liq barcha optimallashtirilgan yo'llar bekor qilinishi kerak).
Amaliy qoida: hech qachon runtime'da (obyekt allaqachon ishlatilayotgan holatda) Object.setPrototypeOf chaqirmang — bu performance uchun eng yomon amaliyotlardan biri hisoblanadi. Agar prototype kerak bo'lsa, uni yaratish paytida (Object.create orqali) belgilang.
7. Xulosa jadval — barcha o'xshash usullarni solishtirish
| Usul | Nima qiladi | Constructor ishga tushadimi |
|---|---|---|
{} |
Yangi obyekt, Object.prototypega avtomatik ulanadi |
Yo'q (constructor umuman yo'q) |
new Fn() |
Yangi obyekt + Fn.prototypega ulanish + constructor bajarilishi |
✅ Ha |
Object.create(proto) |
Yangi obyekt + protoga to'g'ridan-to'g'ri ulanish |
❌ Yo'q |
Object.create(null) |
Yangi, zanjirsiz obyekt | ❌ Yo'q |
Object.setPrototypeOf(obj, proto) |
Mavjud obyektning prototype'ini o'zgartirish | ❌ Yo'q (lekin SEKIN — Hidden Class qayta quriladi) |
Xulosa
Object.create(proto) — bu eng sof, to'g'ridan-to'g'ri yo'l bilan prototype bog'lash: u yangi obyekt yaratadi va uning [[Prototype]]ini siz bergan protoga ulaydi, hech qanday constructor logikasi va side-effect'siz — bu uni new Fn()dan farqlaydigan asosiy xususiyat. U ayniqsa klassik inheritance zanjiri qurishda (Dog.prototype = Object.create(Animal.prototype)) va zanjirsiz, xavfsiz obyektlar (Object.create(null)) yaratishda ishlatiladi.