Mundarija (37)
- Bu darsda
- 1. Nega bu kerak?
- 2. Birinchi klass
- 2.1 Konstruktor funksiyadan klassga
- 2.2 Klass ichidan: o'sha prototip
- 2.3 new qadamma-qadam
- 3. constructor haqida batafsil
- 3.1 U ixtiyoriy
- 3.2 Faqat bitta
- 3.3 return yozmang
- 4. Metodlar va this
- 4.1 Metod ichida this
- 4.2 Metodni ajratib olsa: this yo'qoladi
- 5. Klass va konstruktor funksiya: farqlari
- 5.1 new majburiy
- 5.2 E'londan oldin ishlatib bo'lmaydi
- 5.3 Tana — doim strict
- 5.4 Metodlar sanalmaydi
- 6. Class expression va klass — qiymat
- 6.1 Klassni o'zgaruvchiga yozish
- 6.2 Klassni funksiyaga uzatish
- 6.3 Qachon klass, qachon oddiy obyekt?
- 7. new bilan tanish o'rnatilgan klasslar
- 8. Ko'p uchraydigan xatolar
- 8.1 Metodlar orasida vergul
- 8.2 Metod oldida function
- 8.3 this. siz xususiyat
- 8.4 new ni unutish, klassni pastda e'lon qilish
- 8.5 Metodni constructor ichida yaratish
- 9. Mashqlar
- 1-mashq (oson): Ichimlik klassi
- 2-mashq (o'rta): Konstruktor funksiyadan klassga
- 3-mashq (qiyin): Klassni tekshirish
- 4-mashq: Vazifalar qadami — Vazifa klassi
- 10. Real ishda
- Xulosa
- Manbalar
JavaScript class sintaksisi: konstruktor, metodlar va new
Qisqacha: Klass (class) — bir xil tuzilishdagi obyektlar uchun qolip:
class Taom { constructor(nom) { this.nom = nom; } tavsifla() { ... } }, nusxa esanew Taom("Osh")bilan yaratiladi. Klass — prototip ustidagi qulay sintaksis:constructorkonstruktor funksiyaning o'rnini, metodlar esaTaom.prototypedagi funksiyalarning o'rnini egallaydi. Farqi — klassninewsiz chaqirib bo'lmaydi va uni e'londan oldin ishlatib bo'lmaydi.
Bu darsda
class,constructorva metodlar bilan klass yozib,newbilan nusxalar yarata olasiz.- Klass ichida aslida qaysi prototip zanjiri qurilishini tushuntira olasiz.
- Klass va oddiy konstruktor funksiyaning farqlarini —
newmajburiyligi, TDZ, metodlar sanalmasligi — bilasiz. - Class expression yozasiz va klassni qiymat sifatida funksiyaga uzata olasiz.
vazifalardagi har vazifaniVazifaklassiga o'tkazasiz — xulq o'zgarmaydi.
Oldin bilishingiz kerak: Konstruktor funksiya va new, Object.create va instanceof, this: to'rt qoida, Temporal Dead Zone.
1. Nega bu kerak?
Konstruktor funksiya darsida taomlar uchun "qolip" yozgan edik. Eslaymiz:
function Taom(nom, narx) {
this.nom = nom;
this.narx = narx;
}
Taom.prototype.tavsifla = function () {
return `${this.nom}: ${this.narx} so'm`;
};
Taom.prototype.chegirmaBer = function (foiz) {
this.narx = this.narx - (this.narx * foiz) / 100;
};
const osh = new Taom("Osh", 35000);
console.log(osh.tavsifla()); // Osh: 35000 so'mKod ishlaydi, lekin uchta noqulayligi bor.
Birinchisi — qolip tarqoq: konstruktor bir joyda, metodlar pastda alohida tayinlashlar bilan. Metod ko'paygan sari ular orasiga boshqa kod kirib qolishi mumkin. Ikkinchisi — Taom oddiy funksiyadek ko'rinadi: Taom("Osh") deb new siz chaqirsangiz, xato chiqmaydi, faqat narsa noto'g'ri joyga yoziladi. Uchinchisi — har metod oldida Taom.prototype. ni qayta-qayta yozish.
Klass shu uchala muammoni hal qiladi. Konstruktor ham, metodlar ham bitta blok ichida turadi; new siz chaqirish darhol xato beradi. Ichida esa o'sha prototip mexanizmi ishlaydi — yangi narsa o'ylab topilmagan. Shuning uchun klassni ko'pincha "prototip ustidagi qulay sintaksis" deyishadi. Bu iborani class ichidan darsida chuqur ochamiz; bugun klassni yozish va ishlatishni o'rganamiz.
Hayotdan o'xshatish: g'isht quyish qolipi. Qolipning o'zi g'isht emas — u g'ishtning shaklini belgilaydi. Har quyishda yangi g'isht chiqadi, hammasi bir xil shaklda, lekin har biri alohida. Klass — qolip, new — quyish, nusxa — g'isht.
09-qismda Custom events darsida class Savat extends EventTarget kodini "shaklini tanib qoling" deb ko'rsatgan edik. Bugundan boshlab bunday kodni o'qiy boshlaysiz.
2. Birinchi klass
2.1 Konstruktor funksiyadan klassga
Xuddi o'sha Taom, klass bilan:
class Taom {
constructor(nom, narx) {
this.nom = nom;
this.narx = narx;
}
tavsifla() {
return `${this.nom}: ${this.narx} so'm`;
}
chegirmaBer(foiz) {
this.narx = this.narx - (this.narx * foiz) / 100;
}
}
const osh = new Taom("Osh", 35000);
osh.chegirmaBer(10);
console.log(osh.tavsifla()); // Osh: 31500 so'm
console.log(osh); // Taom { nom: 'Osh', narx: 31500 }Qatorma-qator:
class Taom { ... }— klass e'loni. Nomi bosh harf bilan, xuddi konstruktor funksiyadek — bu "newbilan chaqiriladi" degan kelishuv.constructor(nom, narx) { ... }— nusxa yaratilganda ishlaydigan maxsus metod. Uning tanasi — eskifunction Taomning tanasi:this— yangi obyekt, unga xususiyatlar yoziladi.tavsifla() { ... }— metod.functionso'zi yo'q, metodlar orasida vergul yo'q — obyekt literalidagi qisqa metod yozuviga o'xshaydi (Shorthand va metodlar), faqat vergulsiz.new Taom("Osh", 35000)— nusxa yaratish. Argumentlarconstructorga boradi.
Nomlash kelishuvi kursdagi funksiya nomlari bilan izchil: klass nomi — ot, birlikda va bosh harf bilan (Taom, Buyurtma, Vazifa), chunki u "nima" ekanini aytadi. Metod nomi esa — fe'l yoki natija nomi (tavsifla, chegirmaBer), chunki u "nima qiladi" degan savolga javob. true/false qaytaradigan metod — "-mi" bilan (bandmi).
Bu kelishuv ko'p tilda bir xil: Java, C#, Python'da ham klass nomi bosh harf bilan yoziladi. Shuning uchun new taom() yoki class taomlar ko'rsangiz, kod ishlasa ham, jamoadoshingiz uni tuzatishni so'raydi.
Nusxa (instance) — klassdan new bilan yaratilgan obyekt. osh — Taom ning nusxasi. Node uni Taom { nom: 'Osh', narx: 31500 } deb, klass nomi bilan ko'rsatadi.
2.2 Klass ichidan: o'sha prototip
Klass yangi tur emas. Tekshiramiz:
class Taom {
constructor(nom) {
this.nom = nom;
}
tavsifla() {
return `Bugun: ${this.nom}`;
}
}
const osh = new Taom("Osh");
console.log(typeof Taom); // function
console.log(Object.getPrototypeOf(osh) === Taom.prototype); // true
console.log(Object.hasOwn(osh, "tavsifla")); // false
console.log(Object.hasOwn(Taom.prototype, "tavsifla")); // true
console.log(osh instanceof Taom); // trueHammasi Konstruktor funksiya darsidagidek:
typeof Taom—"function". Klass — maxsus turdagi funksiya.oshning prototipi —Taom.prototype.- Metod nusxada emas,
Taom.prototypeda. Ming nusxa bo'lsa hamtavsiflabitta. instanceofObject.createvainstanceofdarsidagidek ishlaydi.
Diagrammada:
flowchart LR
K["class Taom"] -- "prototype" --> P["Taom.prototype<br/>constructor, tavsifla"]
O1["osh<br/>nom: Osh"] --> P
O2["manti<br/>nom: Manti"] --> P
P --> OP["Object.prototype"]Uzluksiz o'qlar — nusxalarning prototip havolasi, prototype yozuvli o'q esa klassning xususiyati. Rasm konstruktor funksiyadagi bilan bir xil: klass faqat yozuvni o'zgartirdi.
Tekshirib ko'ring: Nusxalar yaratilgandan keyin
Taom.prototype.yangiMetod = function () { return "yangi"; }qo'shilsa,osh.yangiMetod()ishlaydimi?
Javob
Ishlaydi va "yangi" qaytaradi. Prototip — jonli havola (Object.create darsidagidek): osh metodni har safar Taom.prototype dan qidiradi, u yerda esa endi yangiMetod bor. Lekin bunday "keyin qo'shish" real kodda yozilmaydi — metodlar klass tanasida tursin, aks holda klassni o'qigan odam to'liq rasmni ko'rmaydi.
2.3 new qadamma-qadam
new Taom("Osh") ichida new ning to'rt qadami bajariladi. Keyingi tugmasi bilan kuzating:
O'zingiz to'ldiring. class Ichimlik { constructor(nom) { this.nom = nom; } } dan keyin typeof Ichimlik — [:function], new Ichimlik("Choy").nom — [:Choy].
Tekshirib ko'ring:
osh.tavsifla === manti.tavsifla(ikkalasiTaomnusxasi) nima qaytaradi? Nega?
Javob
true. Ikkala nusxada ham tavsifla yo'q — ikkalasi uni bitta joydan, Taom.prototype dan oladi. Bu bitta funksiya. Agar metodni constructor ichida this.tavsifla = function () {...} deb yozsangiz, javob false bo'lardi: har nusxaga alohida funksiya yaratilardi.
3. constructor haqida batafsil
3.1 U ixtiyoriy
Nusxaga boshlang'ich ma'lumot kerak bo'lmasa, constructor yozilmaydi. JavaScript bo'sh konstruktorni o'zi qo'shadi:
class Kassa {
salomBer() {
return "Xush kelibsiz, «Bahor»ga!";
}
}
const kassa = new Kassa();
console.log(kassa.salomBer()); // Xush kelibsiz, «Bahor»ga!
console.log(kassa); // Kassa {}3.2 Faqat bitta
Bitta klassda ikkita constructor bo'lmaydi — SyntaxError: A class may only have one constructor ("klassda faqat bitta konstruktor bo'lishi mumkin"). Har xil argumentlar bilan yaratish kerak bo'lsa — default parametrlar yordam beradi:
class Buyurtma {
constructor(taom, soni = 1, stol = null) {
this.taom = taom;
this.soni = soni;
this.stol = stol;
}
}
console.log(new Buyurtma("Osh"));
console.log(new Buyurtma("Ko'k choy", 2, 5));Konsolda:
Buyurtma { taom: 'Osh', soni: 1, stol: null }
Buyurtma { taom: "Ko'k choy", soni: 2, stol: 5 }Parametr ko'p bo'lsa, options obyekti va destructuring bilan yozish o'qishga qulayroq: constructor({ taom, soni = 1, stol = null }).
Tekshirib ko'ring:
new Buyurtma("Manti", undefined, 3)qanday obyekt yaratadi?
Javob
Buyurtma { taom: 'Manti', soni: 1, stol: 3 }. Default qiymat argument undefined bo'lganda ishlaydi — yozilmagan bo'lsa ham, ataylab undefined berilgan bo'lsa ham (Parametrlar va default qiymatlar). null berilsa esa default ishlamaydi — soni: null bo'lardi.
3.3 return yozmang
Konstruktor odatda hech narsa qaytarmaydi — new yangi obyektni o'zi qaytaradi. Konstruktorda return { ... } yozilsa, new yangi nusxa o'rniga o'sha obyektni qaytaradi va u klass nusxasi bo'lmaydi. Ko'ring:
class Taom {
constructor(nom) {
this.nom = nom;
return { nom: "Boshqa" }; // ❌ shunday yozmang
}
tavsifla() {
return this.nom;
}
}
const osh = new Taom("Osh");
console.log(osh); // { nom: 'Boshqa' }
console.log(osh instanceof Taom); // false
console.log(typeof osh.tavsifla); // undefinedosh — Taom emas, oddiy obyekt: metodi ham yo'q. Bunday kod chalkash — uni yozmang. Bu qoida konstruktor funksiyada ham xuddi shunday edi.
4. Metodlar va this
4.1 Metod ichida this
Metod ichidagi this — metod chaqirilgan nusxa (this: to'rt qoida). Bitta metod boshqasini ham this orqali chaqiradi:
class Taom {
constructor(nom, narx) {
this.nom = nom;
this.narx = narx;
}
qqsBilan() {
return this.narx * 1.12;
}
chekQatori() {
return `${this.nom}: ${this.qqsBilan()} so'm, QQS bilan`;
}
}
const manti = new Taom("Manti", 30000);
console.log(manti.chekQatori()); // Manti: 33600 so'm, QQS bilanBu yerda metodlar bir-biriga tayanib ishlaydi: chekQatori narxni o'zi hisoblamaydi, qqsBilan dan so'raydi. Ertaga QQS stavkasi o'zgarsa, bitta metodni tuzatasiz — chek qatori o'zi yangisini oladi. Ma'lumot (nom, narx) va unga tegishli amallar bitta qolipda yashashining asosiy foydasi shu.
chekQatori ichida qqsBilan() emas, this.qqsBilan(). Metod nusxaning o'zida emas, prototipda — unga faqat obyekt orqali yetib boriladi. this. siz yozsangiz, JavaScript oddiy o'zgaruvchi qidiradi va ReferenceError: qqsBilan is not defined beradi.
4.2 Metodni ajratib olsa: this yo'qoladi
this yo'qolishi darsidagi tuzoq klassda ham bor — va ancha aniq ko'rinadi:
class Taom {
constructor(nom) {
this.nom = nom;
}
tavsifla() {
return `Bugun: ${this.nom}`;
}
}
const osh = new Taom("Osh");
const tavsif = osh.tavsifla;
console.log(tavsif());TypeError: Cannot read properties of undefined (reading 'nom')Tarjimasi: "undefined ning nom xususiyatini o'qib bo'lmaydi". tavsif() — obyektsiz chaqiruv, this — undefined. Klass tanasi doim strict mode da ishlaydi, shuning uchun this hech qachon globalThis ga aylanmaydi — xato darhol chiqadi. Oddiy funksiyada esa jimgina noto'g'ri natija bo'lishi mumkin edi.
Yechimlar o'sha darsdagidek: o'ram (() => osh.tavsifla()) yoki osh.tavsifla.bind(osh) (call, apply, bind). Klassning o'zida ham bitta yo'l bor — uni keyingi darsda, Class maydonlari da ko'ramiz.
Tekshirib ko'ring:
[osh, manti].map((t) => t.tavsifla())ishlaydimi?[osh, manti].map(Taom.prototype.tavsifla)chi?
Javob
Birinchisi ishlaydi: har chaqiruv t.tavsifla() shaklida, this — t. Ikkinchisi — TypeError: map metodni obyektsiz chaqiradi, this — undefined. Callback imzosi darsidagi thisArg bilan (map(fn, osh)) ham chiqmaydi — hamma elementda this bitta osh bo'lib qoladi.
5. Klass va konstruktor funksiya: farqlari
Klass "shakar" bo'lsa ham, uning bir nechta qat'iy qoidasi bor. To'rttasini hozir bilish kerak, qolganlari — class ichidan darsida.
5.1 new majburiy
class Taom {
constructor(nom) {
this.nom = nom;
}
}
const osh = Taom("Osh");TypeError: Class constructor Taom cannot be invoked without 'new'Tarjimasi: "Taom klass konstruktorini new siz chaqirib bo'lmaydi". Konstruktor funksiya bu holatda jim qolardi — klass esa xatoni darhol ko'rsatadi.
5.2 E'londan oldin ishlatib bo'lmaydi
function e'loni "ko'tariladi" — uni fayl boshida ham chaqirsa bo'ladi (Hoisting). Klass esa let va const kabi: e'lon qatorigacha TDZ da turadi.
const osh = new Taom("Osh");
class Taom {
constructor(nom) {
this.nom = nom;
}
}ReferenceError: Cannot access 'Taom' before initializationTarjimasi: "Taom ga ishga tushirilishidan oldin murojaat qilib bo'lmaydi". Klass bor — lekin hali tayyor emas. Qoida: klassni ishlatadigan koddan yuqorida e'lon qiling. Bu darsning vazifalar qadamida aynan shu qoida kerak bo'ladi.
5.3 Tana — doim strict
Klass ichidagi hamma kod strict mode da ishlaydi, faylning boshida "use strict" bo'lmasa ham. Oddiy <script> da ham. «Metodni ajratib olsa» bo'limidagi aniq TypeError — shuning natijasi.
5.4 Metodlar sanalmaydi
Konstruktor funksiyada Taom.prototype.tavsifla = ... oddiy tayinlash edi — metod sanaladigan bo'lardi va for...in da chiqardi. Klass metodlari esa sanalmaydi:
class Taom {
constructor(nom) {
this.nom = nom;
}
tavsifla() {
return this.nom;
}
}
for (const kalit in new Taom("Osh")) {
console.log(kalit); // nom
}for...in faqat nom ni berdi — metod o'rnatilgan metodlar kabi "yashirin". Xuddi polyfill uchun defineProperty bilan qilganimizdek, klass buni o'zi qiladi.
Jadvalda:
| Xususiyat | function Taom |
class Taom |
|---|---|---|
new siz chaqirish |
jim, noto'g'ri natija | TypeError |
| E'londan oldin ishlatish | mumkin (hoisting) | ReferenceError (TDZ) |
| Strict mode | faylga bog'liq | doim |
Metodlar for...in da |
ko'rinadi | ko'rinmaydi |
Tekshirib ko'ring: Nega klass nomini
newsiz chaqirish xatosi foydali?
Javob
Konstruktor funksiyani new siz chaqirsangiz, this noto'g'ri joyni ko'rsatadi (oddiy rejimda — global obyektni) va this.nom = nom global o'zgaruvchi yaratib yuboradi. Natija — undefined va qayerdadir "sirli" global. Xato bir necha qadam keyin, boshqa joyda ko'rinadi. Klass esa xatoni o'sha qatorning o'zida, aniq xabar bilan beradi.
6. Class expression va klass — qiymat
6.1 Klassni o'zgaruvchiga yozish
Funksiyadagidek, klassni ifoda sifatida ham yozish mumkin (Function expression):
const Ichimlik = class {
constructor(nom) {
this.nom = nom;
}
};
const choy = new Ichimlik("Ko'k choy");
console.log(choy); // Ichimlik { nom: "Ko'k choy" }
console.log(Ichimlik.name); // IchimlikClass expression — o'zgaruvchiga yoki argumentga beriladigan klass. Nomni JavaScript o'zgaruvchidan oladi. Amalda klass e'loni (class Ichimlik {}) ko'proq uchraydi; ifoda shakli — klassni boshqa joyga uzatish kerak bo'lganda.
6.2 Klassni funksiyaga uzatish
Klass — funksiya, funksiya esa qiymat (Callback va HOF). Demak klassni argument qilib berish mumkin:
class Taom {
constructor(nom) {
this.nom = nom;
}
}
class Ichimlik {
constructor(nom) {
this.nom = nom;
}
}
function hammasiniYarat(Klass, nomlar) {
return nomlar.map((nom) => new Klass(nom));
}
console.log(hammasiniYarat(Taom, ["Osh", "Manti"]));
console.log(hammasiniYarat(Ichimlik, ["Ko'k choy"]));Konsolda:
[ Taom { nom: 'Osh' }, Taom { nom: 'Manti' } ]
[ Ichimlik { nom: "Ko'k choy" } ]hammasiniYarat qaysi klass kelishini bilmaydi — u faqat "new bilan chaqiraman" deydi. Parametr nomi bosh harf bilan (Klass) — "bu yerga klass keladi" degan ishora.
Tekshirib ko'ring:
hammasiniYarat(Taom, [])nima qaytaradi? Klass bir marta ham chaqiriladimi?
Javob
Bo'sh massiv []. map bo'sh massivda callback'ni umuman chaqirmaydi (map) — demak new Klass(...) ham bir marta ham bajarilmaydi. Natija — xatosiz bo'sh ro'yxat, aynan kutilganidek.
6.3 Qachon klass, qachon oddiy obyekt?
Klassni o'rgangan zahoti hamma narsani klass qilib yozish istagi paydo bo'ladi. Shoshilmang. Uchta savol yordam beradi:
- Bir xil tuzilishdagi obyekt ko'pmi? Vazifalar, taomlar, buyurtmalar — yuzlab nusxa, hammasida bir xil xususiyatlar. Ha — klass foydali. «Bahor» sozlamalari esa bitta obyekt; uni klass qilish ortiqcha — oddiy literal yetadi.
- Ma'lumot bilan birga xulq ham bormi?
almashtir(),chegirmaBer()kabi metodlar ma'lumotning o'zini o'zgartirsa — ular bitta joyda tursin. Faqat ma'lumot bo'lsa (masalan, serverdan kelgan javob) — oddiy obyekt qulayroq: uni JSON'ga aylantirish ham, nusxalash ham oson. - Funksiya yetmaydimi? Ichida holat saqlamaydigan hisob-kitob —
narxniHisobla(taom, soni)— oddiy funksiya bo'lib qolsin. Uni klass metodiga aylantirish faqat chaqirishni qiyinlashtiradi.
JavaScript'da klass — vositalardan biri, majburiy uslub emas. Tajribali jamoalar ham funksiyalar, oddiy obyektlar va klasslarni aralash ishlatadi. Har birining o'rnini OOP tamoyillari va kompozitsiya darsida chuqurroq muhokama qilamiz.
7. new bilan tanish o'rnatilgan klasslar
Endi siz ilgari ko'rgan new lar ham tushunarli: new Date(), new Map() (Map — keyinroq), new DocumentFragment(), new CustomEvent("ozgardi"). Bularning hammasi — brauzer yoki JavaScript tayyorlab qo'ygan klasslar (yoki xuddi klassdek ishlaydigan konstruktorlar). new ularning nusxasini yaratadi, metodlar esa ularning prototipida yashaydi.
Teskari tomoni ham bor: O'rnatilgan prototiplar darsida BigInt va Symbol ni new bilan chaqirib bo'lmasligini ko'rdik — ular klass emas, primitiv qaytaradigan funksiyalar.
09-qismdagi Savat ga qaytaylik:
class Savat extends EventTarget {
taomlar = [];
qosh(taom) {
this.taomlar.push(taom);
this.dispatchEvent(
new CustomEvent("ozgardi", { detail: this.taomlar }),
);
}
}Endi uning katta qismini o'qiy olasiz: class Savat, qosh metodi, this.taomlar, new CustomEvent. Ikkita yangi narsa qoldi. taomlar = [] — konstruktorsiz e'lon qilingan xususiyat, uni keyingi darsda o'rganamiz. extends EventTarget — meros, u Meros: extends va super darsida.
8. Ko'p uchraydigan xatolar
8.1 Metodlar orasida vergul
class Taom {
tavsifla() {
return "osh";
},
narxla() {
return 35000;
}
}SyntaxError: Unexpected token ','Tarjimasi: "kutilmagan belgi: ,". Obyekt literalidagi odat — klass ichida vergul yo'q. Tuzatish: vergulni o'chiring.
8.2 Metod oldida function
class Taom {
function tavsifla() {
return "osh";
}
}SyntaxError: Unexpected identifier 'tavsifla'Tarjimasi: "kutilmagan nom: tavsifla". JavaScript function ni metod nomi deb o'qidi, undan keyin esa ( kutgan edi — tavsifla ni emas. Xabar xato bo'lmagan so'zni ko'rsatadi: oldingi so'zni tekshiring. Tuzatish: function ni o'chiring.
8.3 this. siz xususiyat
class Taom {
constructor(nom) {
this.nom = nom;
}
tavsifla() {
return `Bugun: ${nom}`;
}
}
console.log(new Taom("Osh").tavsifla());ReferenceError: nom is not definedTarjimasi: "nom aniqlanmagan". nom parametri faqat constructor ichida yashaydi. Boshqa metodda u yo'q — u yerda faqat this.nom bor. Tuzatish: ${this.nom}.
8.4 new ni unutish, klassni pastda e'lon qilish
«Farqlari» bo'limidagi ikki xato: Class constructor Taom cannot be invoked without 'new' va Cannot access 'Taom' before initialization. Tuzatish: new Taom(...) va klass e'lonini fayl tepasiga ko'chirish.
8.5 Metodni constructor ichida yaratish
Konstruktor funksiyadan ko'chirayotganda ba'zan shunday kod chiqadi:
class Taom {
constructor(nom) {
this.nom = nom;
this.tavsifla = function () { // ❌ har nusxaga yangi funksiya
return this.nom;
};
}
}Kod ishlaydi, lekin metod endi prototipda emas — har nusxaning o'zida. Ming taom — ming bir xil funksiya xotirada. console.log ham nusxani Taom { nom: 'Osh', tavsifla: [Function (anonymous)] } deb ifloslab ko'rsatadi va JSON.stringify uni tashlab yuboradi. Tuzatish: metodni klass tanasiga, constructor dan tashqariga chiqaring. Konstruktor faqat ma'lumot (xususiyatlar) bilan shug'ullansin, xulq — metodlarda.
9. Mashqlar
1-mashq (oson): Ichimlik klassi
Ichimlik klassini yozing: constructor(nom, narx), tavsifla() metodi "Ko'k choy: 5000 so'm" ko'rinishida satr qaytarsin. Ikki nusxa yaratib, tavsifini chiqaring.
Yechim
class Ichimlik {
constructor(nom, narx) {
this.nom = nom;
this.narx = narx;
}
tavsifla() {
return `${this.nom}: ${this.narx} so'm`;
}
}
const choy = new Ichimlik("Ko'k choy", 5000);
const ayron = new Ichimlik("Ayron", 7000);
console.log(choy.tavsifla()); // Ko'k choy: 5000 so'm
console.log(ayron.tavsifla()); // Ayron: 7000 so'mAyron narxi — misol uchun; «Bahor» kanonik menyusida faqat ko'k choy narxi bor.
2-mashq (o'rta): Konstruktor funksiyadan klassga
Quyidagi kodni klassga o'tkazing. Natija o'zgarmasin.
function Stol(raqam, joylar) {
this.raqam = raqam;
this.joylar = joylar;
this.band = false;
}
Stol.prototype.bandQil = function () {
this.band = true;
};
Stol.prototype.sigadimi = function (odam) {
return !this.band && odam <= this.joylar;
};Ishora: constructor ga funksiya tanasi, metodlarga Stol.prototype. siz nomlar. Predikat nomi "-mi" bilan qoladi.
Yechim
class Stol {
constructor(raqam, joylar) {
this.raqam = raqam;
this.joylar = joylar;
this.band = false;
}
bandQil() {
this.band = true;
}
sigadimi(odam) {
return !this.band && odam <= this.joylar;
}
}
const stol = new Stol(5, 4);
console.log(stol.sigadimi(3)); // true
stol.bandQil();
console.log(stol.sigadimi(3)); // falseUchta tarqoq bo'lak bitta blokka yig'ildi. Ichida — o'sha Stol.prototype va o'sha ikki metod.
3-mashq (qiyin): Klassni tekshirish
Taom klassi uchun quyidagilarni kod bilan isbotlang: (1) tavsifla nusxada emas, prototipda; (2) metod sanalmaydi; (3) Taom.prototype.constructor === Taom. Ishora: Object.hasOwn, Object.keys, Object.getOwnPropertyNames (Xususiyat deskriptorlari).
Yechim
class Taom {
constructor(nom) {
this.nom = nom;
}
tavsifla() {
return this.nom;
}
}
const osh = new Taom("Osh");
const proto = Taom.prototype;
console.log(Object.hasOwn(osh, "tavsifla")); // false
console.log(Object.hasOwn(proto, "tavsifla")); // true
console.log(Object.keys(proto)); // []
console.log(Object.getOwnPropertyNames(proto));
console.log(proto.constructor === Taom); // trueKonsolda to'rtinchi qator: [ 'constructor', 'tavsifla' ]. Object.keys bo'sh — ikkalasi ham sanalmaydi; getOwnPropertyNames esa sanalmaydiganlarni ham beradi. constructor xususiyati — xuddi konstruktor funksiyadagidek, klassga qaytuvchi havola.
4-mashq: Vazifalar qadami — Vazifa klassi
vazifalar ga qaytamiz. Hozir har vazifa — oddiy obyekt. Boshlang'ich uchtasi muzlatilgan boshlangichVazifalar da turadi (Obyektni himoyalash), yangisi vazifaQosh da literal bilan yasaladi. O'zgartirish esa vazifadan tashqarida, spread bilan (Immutable yangilash):
function vazifaQosh(matn) {
holat.vazifalar = [
...holat.vazifalar,
{ id: yangiId(), matn, bajarildi: false },
];
// ...
}
function vazifaniAlmashtir(id) {
const bajarildi = !vazifaniTop(id).bajarildi;
vazifaniYangila(id, { bajarildi });
render();
}Vazifa qolipi — id, matn, bajarildi — bir necha joyda takrorlangan, "belgilash" esa vazifadan tashqarida. Bu — klass uchun aniq nomzod. Object.create darsidagi mashq aynan shunga tayyorgarlik edi.
Yangi branch: git switch -c refactor/vazifa-klassi. refactor/ — xulq o'zgarmaydi. Bu va keyingi ikki dars shu branch'da davom etadi.
Vazifaklassini yozing:constructor(id, matn, bajarildi = false)vaalmashtir()metodi.holat.vazifalarniboshlangichVazifalardannew Vazifa(...)bilan yasang.boshlangichVazifalarning o'zi muzlatilgan oddiy ma'lumot bo'lib qolsin.vazifaQosh,vazifaniAlmashtirvamatnniAlmashtirni klassdan foydalanadigan qiling.- Klassni faylning qayeriga qo'yish kerakligini «E'londan oldin ishlatib bo'lmaydi» bo'limiga qarab hal qiling.
Ishora: vazifaniYangila ichidagi spread ({ ...vazifa, ...ozgarish }) Vazifa nusxasidan qanday obyekt yasaydi? Avval Node'da sinab ko'ring.
Yechim
Avval ishora. Spread obyektning faqat o'z xususiyatlarini ko'chiradi, prototipini emas (Spread va rest):
class Vazifa {
constructor(id, matn, bajarildi = false) {
this.id = id;
this.matn = matn;
this.bajarildi = bajarildi;
}
almashtir() {
this.bajarildi = !this.bajarildi;
}
}
const non = new Vazifa(1, "Non olish");
const nusxa = { ...non, bajarildi: true };
console.log(nusxa); // { id: 1, matn: 'Non olish', bajarildi: true }
console.log(nusxa instanceof Vazifa); // false
console.log(typeof nusxa.almashtir); // undefinednusxa — oddiy obyekt: unda na Vazifa nomi, na almashtir metodi bor. Metod Vazifa.prototype da edi, spread esa prototipga qaramaydi. vazifaniYangila ilovada qolsa, birinchi belgilashdan keyin ro'yxatda Vazifa nusxalari va oddiy obyektlar aralashib ketardi.
Qoida: klass nusxasi spread bilan nusxalanmaydi — uni o'z metodi o'zgartiradi. O'zgarish klass ichida, nazorat ostida bo'ladi — buni Private # maydon darsida mustahkamlaymiz. Immutable yangilash usuli esa yo'qolmaydi: u oddiy ma'lumot uchun qoladi — muzlatilgan boshlangichVazifalar va eksport paketi shunday.
Klass — vazifalar.js ning eng boshiga, "1. Holat" bo'limidan oldin:
// 0. Vazifa klassi — har vazifa shu qolipdan yasaladi
class Vazifa {
constructor(id, matn, bajarildi = false) {
this.id = id;
this.matn = matn;
this.bajarildi = bajarildi;
}
almashtir() {
this.bajarildi = !this.bajarildi;
}
}Holat va uch funksiya:
const holat = {
vazifalar: boshlangichVazifalar.map(
(v) => new Vazifa(v.id, v.matn, v.bajarildi),
),
filtr: "hammasi",
tahrirId: null,
// qoldi getter'i — avvalgidek
};
function vazifaQosh(matn) {
holat.vazifalar = [
...holat.vazifalar,
new Vazifa(yangiId(), matn),
];
if (holat.filtr === "bajarilgan") {
holat.filtr = "hammasi";
}
render();
}
function vazifaniAlmashtir(id) {
vazifaniTop(id).almashtir();
render();
}
function matnniAlmashtir(id, matn) {
vazifaniTop(id).matn = matn;
holat.tahrirId = null;
render();
}vazifaniYangila ni endi hech kim chaqirmaydi — uni o'chiring. vazifaniOchir (filter) o'zgarmaydi: u massivni yangisiga almashtiradi, vazifalarning o'ziga tegmaydi.
Nima o'zgardi va nima o'zgarmadi:
- Joylashuv muhim. Klassni
holatdan pastga qo'ysangiz, sahifa ochilishi bilan konsoldaUncaught ReferenceError: Cannot access 'Vazifa' before initializationchiqadi va ro'yxat bo'sh qoladi —holatklass tayyor bo'lmasdan uni chaqiradi (TDZ). boshlangichVazifalarga tegilmadi.mapundan yangiVazifanusxalarini yasaydi. Belgilash nusxani o'zgartiradi, muzlatilgan ma'lumot esa butun qoladi: Console'daboshlangichVazifalar[0].bajarildi— hamonfalse.bajarildi = false— default parametr. Yangi vazifa doim bajarilmagan, faqat boshlang'ich ma'lumotdatruebo'lishi mumkin.- Qolgan kod tegilmadi.
vazifa.id,vazifa.matn,vazifa.bajarildini o'qiydigan hamma joy —mosmi,qatorYasa,statistika,xatoniTop— avvalgidek ishlaydi: nusxada ham o'sha uch xususiyat bor. - Eksport natijasi ham o'zgarmadi — metod prototipda,
JSON.stringifyesa faqat o'z xususiyatlarni oladi (JSON asoslari).
Xulq o'zgarmaganini tekshiring (Live Server):
- Ochilganda — uch vazifa, "2 ta vazifa qoldi, 1 ta bajarildi", konsolda xato yo'q.
- «Faol» da ikkala vazifani
Spacebilan belgilang — "Faol vazifa yo'q.", fokus "Ro'yxat" sarlavhasida. - Yangi vazifa qo'shing, uni belgilang va qaytaring — hisob to'g'ri o'zgaradi. Uni tahrirlab
Enterbosing — matn yangilanadi. Esc, o'chirish, takror matn xatosi va eksport — avvalgidek.
Commit: Vazifalar: vazifani Vazifa klassiga o'tkaz. Branch'ni hali main ga qo'shmang.
10. Real ishda
- Brauzer va Node API'lari — deyarli hammasi klass:
Map,Date,URL,Error,EventTarget, DOM elementlari. Ularning hujjatini o'qiganda "constructor", "instance methods" bo'limlari — aynan bugungi tushunchalar. - Freymvorklar. Angular va NestJS (30-qismda) kodning asosiy qismini klasslarda yozadi. React'da hozir funksiya komponentlar asosiy, lekin eski loyihalarda
class App extends React.Componentni ko'p uchratasiz. - Domen modellari. Real ilovalarda biznes tushunchalari —
Buyurtma,Foydalanuvchi,Tolov— ko'pincha klass bo'ladi: ma'lumot va qoidalar (masalan, "to'langan buyurtmani bekor qilib bo'lmaydi") bir joyda. Bu yondashuv 30-qismdagi NestJS va backend arxitekturasida asosiy uslub. - TypeScript (15-qism) klasslarga turlar va kirish modifikatorlarini qo'shadi — bugungi sintaksis uning poydevori.
- Intervyu. "Klass va konstruktor funksiya farqi?", "Klass hoisting bo'ladimi?", "Metodlar qayerda saqlanadi?" — hammasining javobi shu darsda. Ko'p intervyuchi qo'shimcha so'raydi: "Klassni konstruktor funksiyaga qo'lda o'girib bering". Endi bu ikki yo'nalishda ham qo'lingizdan keladi — «Konstruktor funksiyadan klassga» bo'limi va 2-mashq aynan shu mashq edi.
Xulosa
- Klass — bir xil tuzilishdagi obyektlar qolipi:
constructor+ metodlar, nusxanewbilan. - Ichida o'sha prototip:
typeof Klass—"function", metodlarKlass.prototypeda, nusxada faqatthis.bilan yozilganlar. - Metodlar orasida vergul va
functionso'zi yo'q; boshqa metod va xususiyatgathis.orqali murojaat qilinadi. - Klassni
newsiz chaqirib bo'lmaydi, e'londan oldin ishlatib bo'lmaydi (TDZ), tanasi doim strict, metodlari sanalmaydi. - Klass — qiymat: uni o'zgaruvchiga yozish va funksiyaga uzatish mumkin.
Keyingi dars: Class maydonlari — xususiyatlarni konstruktorsiz, klass tanasida e'lon qilishni va this yo'qolishini arrow maydon bilan hal qilishni (va uning narxini) o'rganamiz.
Manbalar
- MDN: "Classes", "constructor", "class expression" — developer.mozilla.org
- ECMAScript 2025 Language Specification: "Class Definitions" — tc39.es/ecma262
- web-features:
class-syntax— Baseline 2016-03 (keng qo'llab-quvvatlanadi 2018-09 dan)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!