Class (Syntactic Sugar)
Class tagida nima yotadi — constructor function + prototype. newsiz chaqirilmasligi, enumerable:false metodlar, TDZ va avtomatik strict mode kabi haqiqiy farqlar.
27-dars
Class (Syntactic Sugar)
1. "Syntactic sugar" nima degani?
class Person {
constructor(name) {
this.name = name;
}
greet() {
return `Salom, men ${this.name}`;
}
}
"Syntactic sugar" — degani: bu yangi mexanizm emas, faqat eski mexanizmni (constructor function + prototype) yozishning yangi, chiroyliroq sintaksisi. V8 ichida class uchun alohida engine yo'q — u parse bosqichida deyarli xuddi constructor function + prototype.method shakliga aylantiriladi.
Buni isbotlash mumkin:
console.log(typeof Person); // 'function' — CLASS ASLIDA FUNKSIYA!
class Person {} yozganingizda ham, typeof Person — 'function' qaytaradi, obyekt yoki boshqa maxsus tur emas. Bu — class'ning tagida hali ham constructor function yotganining isboti.
2. Class qanday "ochiladi" (desugar qilinsa)
class Person {
constructor(name) {
this.name = name;
}
greet() {
return `Salom, men ${this.name}`;
}
}
Bu — deyarli aynan quyidagiga teng:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `Salom, men ${this.name}`;
};
const p1 = new Person('Ali');
console.log(p1.greet()); // ikkalasida ham bir xil natija
console.log(p1.__proto__ === Person.prototype); // true — ikkalasida ham
Class ichidagi metodlar (greet()) — avtomatik ravishda Person.prototypega qo'shiladi, xuddi qo'lda Person.prototype.greet = ... yozgandagidek. Bu — xotira tejash (bitta metod, barcha instance bo'lishadi) hali ham class'da ham amal qiladi, chunki tagida bir xil mexanizm ishlaydi.
3. Farqlar — class va constructor function butunlay bir xil emas!
Garchi tagida bir xil mexanizm yotsa ham, class bir nechta qo'shimcha, qat'iy qoidalar kiritadi. Bular — haqiqiy farqlar, faqat "sintaksis" emas:
Farq 1 — newsiz chaqirib bo'lmaydi
class Person {
constructor(name) { this.name = name; }
}
Person('Ali'); // TypeError: Class constructor Person cannot be invoked without 'new'
Oddiy constructor function esa newsiz ham (noto'g'ri, lekin) chaqirilib ketaveradi. Class bu xatoni V8 darajasida oldindan bloklaydi — bu ataylab kiritilgan xavfsizlik.
Farq 2 — Class metodlari enumerable: false
function Person(name) { this.name = name; }
Person.prototype.greet = function() {};
console.log(Object.getOwnPropertyDescriptor(Person.prototype, 'greet').enumerable); // true
class PersonClass {
greet() {}
}
console.log(Object.getOwnPropertyDescriptor(PersonClass.prototype, 'greet').enumerable); // false!
enumerable: false degani for...in va Object.keys()da ko'rinmaydi degani edi. Class metodlari avtomatik shunday qilib yaratiladi — chunki built-in metodlar (masalan Array.prototype.push) ham xuddi shunday, enumerable: false. Bu — class'ning constructor function'dan haqiqiy, texnik farqi, shunchaki sintaksis emas.
for (let key in new PersonClass()) {
console.log(key); // greet HECH QACHON ko'rinmaydi
}
Farq 3 — Temporal Dead Zone (TDZ), Hoisting yo'q
const p1 = new Person('Ali'); // ✅ ishlaydi, chunki function hoisting bor
function Person(name) { this.name = name; }
const p2 = new PersonClass('Ali'); // ❌ ReferenceError: Cannot access before initialization
class PersonClass { constructor(name) { this.name = name; } }
Class hoisting bo'ladi (nomi biladi), lekin let/const kabi TDZ (Temporal Dead Zone) ga ega — e'lon qatoridan oldin foydalanib bo'lmaydi.
Farq 4 — Class tanasi avtomatik strict mode da ishlaydi
class Person {
constructor(name) {
this.name = name;
undeclaredVar = 5; // ReferenceError — strict mode avtomatik yoqilgan!
}
}
Oddiy funksiyada 'use strict' yozilmasa, bunday xato sokin o'tib ketardi (global o'zgaruvchi yaratilardi). Class ichida bu har doim, avtomatik strict mode — dasturchi buni o'zgartira olmaydi.
4. Getter/Setter class ichida — Property Descriptor bilan bog'lanish
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
set fullName(value) {
[this.firstName, this.lastName] = value.split(' ');
}
}
Bu — Accessor Descriptorning class ichidagi yozilishi. Ichkarida bu xuddi Object.defineProperty(Person.prototype, 'fullName', { get, set }) ga teng — faqat qulayroq sintaksis bilan.
5. constructor() — bu maxsus, ajratilgan metod
class Person {
constructor(name) {
this.name = name; // BU YERDA property qo'shiladi (Hidden Class C1 {name})
}
}
constructor — class ichida maxsus nom sifatida ishlaydi. Uning ichidagi kod — parse qilinganda, aynan funksiya tanasiga aylanadi (Person.call(newObj, ...) bosqichida bajariladigan kod). Class ichidagi boshqa metodlar (greet()) esa — prototypega qo'shiladigan alohida funksiyalar.
class Person {
constructor(name) { ... } → function Person(name) { ... }
greet() { ... } → Person.prototype.greet = function() { ... }
}
Agar constructor yozilmasa, V8 bo'sh constructorni avtomatik yaratadi:
class Empty {}
// avtomatik ravishda:
// function Empty() {}
6. Xulosa jadval — Class vs Constructor Function
| Xususiyat | Constructor Function | Class |
|---|---|---|
| Tagida nima yotadi | Funksiya + prototype | Xuddi shu (ichkarida) |
typeof natija |
'function' |
'function' |
newsiz chaqirish |
Ruxsat (xavfli, sokin xato) | TypeError — bloklanadi |
| Metodlar enumerable | true (default) |
false (avtomatik) |
| Hoisting | To'liq (butun funksiya) | Faqat nom, TDZ bor |
| Strict mode | Qo'lda yoqish kerak | Avtomatik, majburiy |
| Getter/setter | defineProperty orqali qo'lda |
get/set sintaksis bilan qulay |