Seriya: JavaScript Basics Dars 26

new keyword ichida nima bo'ladi?

new operatori bajaradigan 4 qadam — yangi obyekt, prototype bog'lash, this bilan chaqirish, return qiymatini tekshirish — va arrow function bilan ishlamasligi.

26-dars

new keyword ichida nima bo'ladi?

1. Yuzaki qarash — bitta qator, lekin 4 ta ish

function Person(name) {
  this.name = name;
}

const p1 = new Person('Ali');

Bu bitta qator ko'rinadi, lekin ichkarida V8 4 ta aniq qadamni ketma-ket bajaradi. Keling har birini alohida ochamiz.


2. new operatori bajaradigan 4 qadam

// new Person('Ali') ICHKARIDA aynan shu bajariladi:

// QADAM 1: Yangi, bo'sh obyekt yaratiladi
const newObj = {};

// QADAM 2: Yangi obyektning [[Prototype]]'i Person.prototype'ga bog'lanadi
Object.setPrototypeOf(newObj, Person.prototype);
// yoki eski uslubda: newObj.__proto__ = Person.prototype;

// QADAM 3: Person funksiyasi chaqiriladi, this = newObj qilib bog'langan holda
const result = Person.call(newObj, 'Ali');

// QADAM 4: Agar Person biror OBYEKT qaytarsa — o'sha qaytariladi.
//           Aks holda (undefined, primitiv qaytarsa) — newObj qaytariladi.
const finalResult = (typeof result === 'object' && result !== null) ? result : newObj;

Keling, har bir qadamni chuqurroq ko'ramiz.

QADAM 1 — Yangi obyekt yaratiladi (Heap'da)

const newObj = {};

V8 heap'da yangi, bo'sh obyekt yaratadi — hozircha Hidden Class C0 {} (bo'sh, hech qanday property yo'q).

HEAP:
newObj {}  ← hali hech narsa yo'q, Hidden Class: C0

QADAM 2 — Prototype bog'lanadi

newObj.[[Prototype]] = Person.prototype;

Aynan shu qadamda p1.__proto__ === Person.prototype bo'lishi ta'minlanadi. Bu — Prototype Chainning boshlanish nuqtasi:

HEAP:
newObj {}
  [[Prototype]] ──→ Person.prototype { greet, constructor }

Muhim: bu bog'lanish — Person funksiyasi ichidagi kod (this.name = name) ishga tushishidan oldin sodir bo'ladi. Ya'ni this — funksiya tanasi bajarilishidan avval allaqachon to'liq shakllangan, prototype'ga ulangan obyekt.

QADAM 3 — Funksiya this = yangi obyekt bilan chaqiriladi

Person.call(newObj, 'Ali');

Bu — call mexanizmi orqali ishlaydi! Person funksiyasi ichidagi this endi newObjga bog'langan. Funksiya tanasi bajariladi:

function Person(name) {
  this.name = name; // this === newObj, shuning uchun: newObj.name = 'Ali'
}

Bu qatorda newObjga yangi property qo'shiladi — bu Transition Chainni ishga tushiradi:

newObj Hidden Class: C0 {} → C1 {name}  (yangi Hidden Class'ga o'tdi)
HEAP:
newObj { name: 'Ali' }
  [[Prototype]] ──→ Person.prototype { greet, constructor }

QADAM 4 — Return qiymati tekshiriladi (eng ko'p e'tibordan chetda qoladigan qism!)

Bu — eng kam odam biladigan, lekin juda muhim qoida:

function Person(name) {
  this.name = name;
  // return yozilmagan — avtomatik "return this" kabi ishlaydi
}

Agar constructor function hech narsa qaytarmasa (yoki undefined, yoki primitiv qiymat qaytarsa) — new operatori avtomatik ravishda thisni (ya'ni newObjni) qaytaradi.

function Person(name) {
  this.name = name;
  return 42; // PRIMITIV qiymat — E'TIBORGA OLINMAYDI!
}

const p1 = new Person('Ali');
console.log(p1.name); // 'Ali' — 42 emas, newObj qaytdi!

Lekin agar constructor OBYEKT qaytarsa — o'sha obyekt newObjning o'rniga qaytariladi:

function Person(name) {
  this.name = name;
  return { name: 'Boshqa obyekt', special: true }; // OBYEKT — bu qaytadi!
}

const p1 = new Person('Ali');
console.log(p1.name);    // 'Boshqa obyekt' — newObj TASHLAB YUBORILDI!
console.log(p1.special); // true
console.log(p1 instanceof Person); // false! — chunki bu newObj emas

Bu qoida spesifikatsiyada aniq belgilangan: agar constructor'ning return qiymati typeof === 'object' (yoki funksiya) bo'lsa va null bo'lmasa — o'sha qiymat ishlatiladi, this (newObj) butunlay tashlab yuboriladi (garbage collector uni yig'ib oladi, chunki hech kim unga ishora qilmay qoladi).


3. To'liq V8 pseudocode — hammasi birga

function NEW(ConstructorFn, ...args) {
  // 1. Yangi bo'sh obyekt
  const newObj = {};

  // 2. Prototype bog'lash
  Object.setPrototypeOf(newObj, ConstructorFn.prototype);

  // 3. Constructor'ni this=newObj bilan chaqirish
  const result = ConstructorFn.apply(newObj, args);

  // 4. Qaytariladigan qiymatni aniqlash
  if (typeof result === 'object' && result !== null) {
    return result; // obyekt qaytgan bo'lsa — o'shani beramiz
  }
  if (typeof result === 'function') {
    return result; // funksiya ham "obyekt" hisoblanadi shu yerda
  }

  return newObj; // aks holda — yaratilgan obyektni qaytaramiz
}

// new Person('Ali')  ekvivalenti:
const p1 = NEW(Person, 'Ali');

4. Nega bu tartib muhim — real xato misoli

function Config(options) {
  this.options = options || {};

  // Xato: dasturchi "agar options bo'sh bo'lsa, default obyekt qaytaray" deb o'ylagan
  if (!options) {
    return {}; // ❌ BU YANGI, BO'SH OBYEKT — Config'ga aloqasi yo'q!
  }
}

const c1 = new Config();
console.log(c1 instanceof Config); // false! — kutilmagan natija
console.log(c1.options); // undefined! — chunki bu newObj emas, boshqa {}

Bu juda muhim tuzoq: constructor ichida hech qachon shartli ravishda obyekt return qilmang, aks holda new operatorining butun mo'ljalini (yangi, to'g'ri bog'langan instance yaratish) buzasiz.


5. Arrow function nega new bilan ishlamaydi?

const Person = (name) => {
  this.name = name;
};

new Person('Ali'); // TypeError: Person is not a constructor

Arrow function larda .prototype umuman yo'q. new operatorining 2-qadami (newObj.[[Prototype]] = Fn.prototype) bajarilishi uchun Fn.prototype mavjud bo'lishi shart. Arrow function'da bu yo'q — shuning uchun V8 new chaqirilishini darhol, ishga tushmasdanoq rad etadi (TypeError).

Bundan tashqari, arrow function'ning o'z thisi yo'q (lexical this ishlatadi) — shuning uchun ham new orqali "yangi this bog'lash" tushunchasi arrow function uchun mantiqan mos emas.


6. Xulosa — 4 qadam, vizual

new Person('Ali')
        │
        ▼
┌───────────────────────────────────────────┐
│ 1. newObj = {}                              │  ← bo'sh obyekt, Heap'da
├───────────────────────────────────────────┤
│ 2. newObj.[[Prototype]] = Person.prototype  │  ← zanjirga ulanadi
├───────────────────────────────────────────┤
│ 3. Person.call(newObj, 'Ali')               │  ← this=newObj, funksiya tanasi ishlaydi
│    → newObj.name = 'Ali'                    │
├───────────────────────────────────────────┤
│ 4. return qiymatini tekshirish:             │
│    - obyekt qaytdimi? → o'shani ber         │
│    - aks holda → newObj'ni ber              │
└───────────────────────────────────────────┘
        │
        ▼
      p1 = newObj (odatda)

Bir gapda: new — bu spetsifikatsiyada qattiq belgilangan 4 qadamli protsedura: bo'sh obyekt yaratish → uni constructor'ning prototypeiga bog'lash → constructor'ni shu obyekt this qilib chaqirish → agar constructor obyekt qaytarsa o'shani, aks holda yaratilgan obyektni natija sifatida berish.