Series: JavaScript Basics Lesson 31

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.