Mundarija (31)
- Bu darsda
- 1. Nega bu kerak?
- 2. Birinchi xato klassi
- 2.1 Kod
- 2.2 Ushlanmasa — Node'da
- 3. name ni qo'yishning uch yo'li
- 4. Qo'shimcha maydonlar
- 4.1 kod: kod o'qiydigan sabab
- 4.2 Server xatolarida status
- 5. catch da turlarni ajratish
- 5.1 instanceof zanjiri
- 5.2 Tartib: avval bola, keyin ota
- 6. Xato ierarxiyasi
- 6.1 Umumiy ota klass
- 6.2 Qancha klass kerak?
- 6.3 Begona xatoni o'z turingizga o'rash
- 7. Brauzerda: maydonni ko'rsatadigan xato
- 8. Ko'p uchraydigan xatolar
- 8.1 name unutilgan
- 8.2 super dan oldin this
- 8.3 sozlama super ga berilmagan
- 8.4 Ota klass bolasidan oldin tekshiriladi
- 8.5 message ni solishtirish
- 9. Mashqlar
- 1-mashq (oson): TolovXatosi
- 2-mashq (o'rta): To'g'ri tartib
- 3-mashq (qiyin): Kod bo'yicha xabar
- 4-mashq: Vazifalar qadami — VazifaXatosi
- 10. Real ishda
- Xulosa
- Manbalar
JavaScript'da o'z xato klasslaringiz: class … extends Error
Qisqacha: O'z xato turingiz —
Errordan meros olgan oddiy klass:class BronXatosi extends Error. Konstruktordasuper(xabar, sozlama)vathis.name = "BronXatosi"yoziladi, kerak bo'lsakodkabi qo'shimcha maydonlar qo'shiladi. Endicatchdaxato instanceof BronXatosibilan o'zingiz tashlagan xatoni boshqa har qanday xatodan (bug'dan) aniq ajratasiz: o'zingiznikini hal qilasiz, qolganini qayta tashlaysiz.
Bu darsda
class … extends Errorbilan o'z xato turingizni yaratasiz vanameni to'g'ri qo'yasiz.- Xatoga
kodva boshqa maydonlar qo'shib, unga kod o'qiy oladigan ma'lumot berasiz. catchdainstanceofbilan bir nechta xato turini to'g'ri tartibda ajratasiz.- Kichik xato ierarxiyasini loyihalaysiz va qachon yangi klass kerak emasligini bilasiz.
vazifalarimportidaVazifaXatosibilan foydalanuvchi xatosini bug'dan ajratasiz.
Oldin bilishingiz kerak: throw va Error obyekti, try / catch / finally, Meros: extends va super, Object.create va instanceof.
1. Nega bu kerak?
O'tgan darsning bron formasida catch shunday edi:
catch (xato) {
if (!(xato instanceof RangeError)) {
throw xato;
}
javob.textContent = xato.message;
}Niyat to'g'ri: "bron qoidalari xatosini ko'rsat, boshqasini qayta tashla". Lekin RangeError — umumiy tur. Uni JavaScript'ning o'zi ham tashlaydi:
try {
(35000).toFixed(200);
} catch (xato) {
console.log(xato instanceof RangeError);
console.log(xato.message);
}Konsolda:
true
toFixed() digits argument must be between 0 and 100Bron kodining ichida kimdir toFixed(200) yozib qo'ydi deylik (bug!). Forma bu inglizcha matnni mehmonga "bron xatosi" sifatida ko'rsatadi. vazifalar importida ham xuddi shu narsani ko'rdik: DevTools'da buzilgan VazifalarRoyxati.dan ning xabari import maydoni yonida chiqdi, konsol esa toza qoldi.
Muammo: biz "bu xatoni men tashladim" degan belgini qo'ya olmayapmiz. RangeError, TypeError, Error — hammasi umumiy. Bizga faqat o'zimiz ishlatadigan tur kerak.
Hayotdan o'xshatish: restorandagi xodimlar formasi. Zalda o'nlab odam bor. Mehmon savol bermoqchi bo'lsa, kimga murojaat qilishni formadan biladi — "«Bahor» xodimi". Formasiz odam — boshqa mehmon, unga buyurtma bermaysiz. O'z xato klassi — xatoning "formasi": catch uni bir qarashda taniydi.
2. Birinchi xato klassi
2.1 Kod
class BronXatosi extends Error {
constructor(xabar, sozlama) {
super(xabar, sozlama);
this.name = "BronXatosi";
}
}
const xato = new BronXatosi("Ko'pi bilan 20 kishi");
console.log(xato.message); // Ko'pi bilan 20 kishi
console.log(xato.name); // BronXatosi
console.log(String(xato)); // BronXatosi: Ko'pi bilan 20 kishi
console.log(xato instanceof BronXatosi); // true
console.log(xato instanceof Error); // trueHar qatorni Meros darsidagi bilimlar bilan o'qiymiz:
extends Error—BronXatosiErrorning bolasi.message,stack,cause— hammasi meros.super(xabar, sozlama)—Errorkonstruktorini chaqiradi. Umessageni yozadi,sozlamadacausebo'lsa — uni ham (throwvaError).superni birinchi chaqiring: undan oldinthisishlatilmaydi.this.name = "BronXatosi"— tur nomi. U konsoldagi xabar boshida chiqadi.instanceofikkalasiga hamtrue: bron xatosi — ham bron xatosi, ham xato (Object.create vainstanceof). Prototip zanjiri:xato→BronXatosi.prototype→Error.prototype→Object.prototype.
Meros darsida TaomTugadiXatosi ni yaratib, "uni tashlash va ushlash keyinroq" degan edik. Endi hammasi bir joyda: yaratish, tashlash, ushlash.
2.2 Ushlanmasa — Node'da
Node ushlanmagan xatoni bizning name bilan chiqaradi. bron.js:
class BronXatosi extends Error {
constructor(xabar, sozlama) {
super(xabar, sozlama);
this.name = "BronXatosi";
this.kod = sozlama?.kod;
}
}
throw new BronXatosi("Ko'pi bilan 20 kishi", { kod: "ODAM_KOP" });node bron.js (yo'l va node:internal qatorlari qisqartirildi):
C:\...\10\bron.js:9
throw new BronXatosi("Ko'pi bilan 20 kishi", { kod: "ODAM_KOP" });
^
BronXatosi: Ko'pi bilan 20 kishi
at Object.<anonymous> (C:\...\10\bron.js:9:7)
at node:internal/main/run_main_module:33:47 {
kod: 'ODAM_KOP'
}Ikki narsaga qarang. Tur — BronXatosi: izni o'qigan dasturchi xato qaysi qoidadan kelganini darhol biladi. Oxirida — { kod: 'ODAM_KOP' }: Node xatoning qo'shimcha maydonlarini ham ko'rsatadi. kod haqida «Qo'shimcha maydonlar» bo'limida gaplashamiz.
Va bitta yaxshi yangilik: izning birinchi at qatori — throw yozilgan joy, BronXatosi konstruktorining ichi emas. V8 (Chrome va Node ichidagi JavaScript dvigateli) meros olingan xato konstruktorlarini izdan o'zi chiqarib tashlaydi.
Tekshirib ko'ring:
class A extends Error {}—new A("x")ningnamei nima?String(new A("x"))nima beradi?
Javob
name — "Error", String(...) — "Error: x". name Error.prototype dan meros: u yerda "Error" yozilgan. Klass nomi o'zi name ga aylanmaydi — uni o'zingiz qo'yishingiz kerak. Buni keyingi bo'limda batafsil ko'ramiz.
3. name ni qo'yishning uch yo'li
name yozilmasa, xato konsolda Error: … bo'lib chiqadi — butun ishimiz behuda:
class TolovXatosi extends Error {}
const xato = new TolovXatosi("Karta rad etildi");
console.log(String(xato)); // Error: Karta rad etildi
console.log(xato instanceof TolovXatosi); // trueinstanceof ishlaydi, lekin konsolni o'qigan odam turini ko'rmaydi. name ni qo'yishning uch keng tarqalgan yo'li:
class A extends Error {
constructor(xabar, sozlama) {
super(xabar, sozlama);
this.name = "A";
}
}
class B extends Error {
name = "B";
}
class C extends Error {
constructor(xabar, sozlama) {
super(xabar, sozlama);
this.name = new.target.name;
}
}
class D extends C {}
console.log(String(new A("a")), String(new B("b")));
console.log(String(new C("c")), String(new D("d")));Konsolda:
A: a B: b
C: c D: d| Yo'l | Afzalligi | Kamchiligi |
|---|---|---|
Konstruktorda this.name = "A" |
Aniq, hamma joyda ishlaydi | Har klassda qayta yoziladi |
Klass maydoni name = "B" |
Qisqa (Class maydonlari) | Konstruktor kerak bo'lsa, baribir yoziladi |
this.name = new.target.name |
Bir marta yoziladi, bolalar ham to'g'ri nom oladi | Siqilgan kodda klass nomi o'zgarishi mumkin |
Uchinchi yo'l — new.target (Konstruktor funksiya va new) — new bilan chaqirilgan klassning o'zi. D uchun u D, garchi konstruktor C da yozilgan bo'lsa ham. Qulay, lekin tuzog'i bor. Stack trace darsida siqilgan kodni ko'rgandik — u yerda funksiya nomlari n, e bo'lib qolgan edi. Klass nomlari ham shunday qisqarishi mumkin, va xato t: Karta rad etildi bo'lib chiqadi.
Bu kursda birinchi yo'lni ishlatamiz: nom matn sifatida yozilgan, hech qanday vosita uni o'zgartirmaydi.
4. Qo'shimcha maydonlar
4.1 kod: kod o'qiydigan sabab
message — odam uchun matn. U o'zgarishi mumkin: imlo tuzatiladi, boshqa tilga tarjima qilinadi. Shuning uchun kod hech qachon message ni solishtirmasligi kerak:
if (xato.message === "Ko'pi bilan 20 kishi") { ... } // ❌ mo'rtErtaga kimdir matnga nuqta qo'shsa, shart jimgina ishlamay qoladi. Kod uchun alohida, o'zgarmas belgi kerak — kod (error code). Node'ning o'zida ham shunday: fayl topilmasa xato.code — "ENOENT" (Stack trace darsidagi ECONNREFUSED ham kod).
class BronXatosi extends Error {
constructor(xabar, sozlama) {
super(xabar, sozlama);
this.name = "BronXatosi";
this.kod = sozlama?.kod ?? "NOMALUM";
this.maydon = sozlama?.maydon;
}
}
function bronniTekshir(odam, vaqt) {
if (odam > 20) {
throw new BronXatosi("Ko'pi bilan 20 kishi.", {
kod: "ODAM_KOP",
maydon: "odam",
});
}
if (vaqt < "10:00" || vaqt > "22:00") {
throw new BronXatosi("Bron 10:00–22:00 da qabul qilinadi.", {
kod: "VAQT_YOPIQ",
maydon: "vaqt",
});
}
}
try {
bronniTekshir(4, "23:30");
} catch (xato) {
console.log(xato.kod, xato.maydon); // VAQT_YOPIQ vaqt
console.log(xato.message); // Bron 10:00–22:00 da qabul qilinadi.
}Uch maydon — uch ish:
message— mehmonga ko'rsatiladi.kod— dastur unga qarab qaror qiladi: statistika, boshqa xabar, boshqa harakat.maydon— formada qaysi maydonni qizil qilish va fokusni qayerga qo'yish.
sozlama obyektiga cause dan tashqari o'z kalitlarimizni ham qo'shdik. Error ularni e'tiborsiz qoldiradi — u sozlamadan faqat cause ni o'qiydi. Qolganini biz konstruktorda olamiz. sozlama?.kod — sozlama berilmagan bo'lsa ham xato yo'q (?. operatori).
Kodlarni KATTA_HARF va pastki chiziq bilan yozish — keng tarqalgan kelishuv (ENOENT, ERR_INVALID_ARG_TYPE). Kod — matn, lekin u "nom" vazifasini bajaradi: bir marta tanlanadi va o'zgartirilmaydi.
4.2 Server xatolarida status
Server dasturlarida xato klassiga ko'pincha HTTP status kodi qo'shiladi: 404 — "topilmadi", 400 — "so'rov noto'g'ri". Status kodlarini HTTP metodlari va status kodlari darsida ko'rgansiz. Server xatoni ushlab, mijozga aynan shu raqamni qaytaradi. Express va NestJS (server yozish freymvorklari — kursda keyinroq) bu naqshni tayyor holda beradi. Hozir faqat g'oyani biling: maydonlar — xatoni ushlaydigan kodga kerakli hamma ma'lumot.
Tekshirib ko'ring: Nega
kodnimessageichiga yozib ("ODAM_KOP: Ko'pi bilan 20 kishi"), keyinsplit(":")bilan ajratish yomon g'oya?
Javob
Matnni bo'lish mo'rt: xabar ichida ikki nuqta bo'lsa (masalan, "10:00"), split noto'g'ri bo'ladi. Foydalanuvchiga ham kod ko'rinib qoladi. Alohida maydon — aniq va xavfsiz: xato.kod ni o'qish uchun hech narsani qirqish kerak emas.
5. catch da turlarni ajratish
5.1 instanceof zanjiri
Endi bir nechta xato turi bor. catch har birini o'z yo'li bilan hal qiladi, notanishini qayta tashlaydi:
class BronXatosi extends Error {
constructor(xabar) {
super(xabar);
this.name = "BronXatosi";
}
}
class TolovXatosi extends Error {
constructor(xabar) {
super(xabar);
this.name = "TolovXatosi";
}
}
function xatoniKorsat(xato) {
if (xato instanceof BronXatosi) {
return `Bronni tekshiring: ${xato.message}`;
}
if (xato instanceof TolovXatosi) {
return `To'lov o'tmadi: ${xato.message}`;
}
throw xato;
}
const xatolar = [
new BronXatosi("stol band"),
new TolovXatosi("karta muddati o'tgan"),
new TypeError("narx.toFixed is not a function"),
];
for (const x of xatolar) {
try {
console.log(xatoniKorsat(x));
} catch (begona) {
console.log("Bug, qayta tashlandi:", begona.name);
}
}Konsolda:
Bronni tekshiring: stol band
To'lov o'tmadi: karta muddati o'tgan
Bug, qayta tashlandi: TypeErrorxatoniKorsat faqat ikki "formali" xatoni taniydi. TypeError — formasiz: u kodda nimadir buzilganini bildiradi, uni foydalanuvchiga chiroyli matn qilib ko'rsatish — bug'ni yashirish. Shuning uchun u qayta tashlandi.
5.2 Tartib: avval bola, keyin ota
Klasslar meros bilan bog'langan bo'lsa, tekshiruv tartibi muhim. instanceof ota klass uchun ham true beradi:
class BahorXatosi extends Error {}
class BronXatosi extends BahorXatosi {}
const xato = new BronXatosi("stol band");
if (xato instanceof BahorXatosi) {
console.log("umumiy xabar"); // umumiy xabar
} else if (xato instanceof BronXatosi) {
console.log("bron xabari");
}Bron xatosi uchun maxsus shox hech qachon ishlamaydi: birinchi shart uni "yutib yubordi". Qoida: aniqroq (bola) klassni avval, umumiyroq (ota) klassni keyin tekshiring. Xuddi if dagi shartlar kabi — tor shart keng shartdan oldin (if / else).
6. Xato ierarxiyasi
6.1 Umumiy ota klass
Loyihada bir nechta xato klassi bo'lsa, ularga umumiy ota beriladi. Shunda "bu bizning loyihamizning xatosimi?" degan savolga bitta tekshiruv javob beradi:
flowchart TD
E["Error"] --> B["BahorXatosi"]
E --> T["TypeError, RangeError …"]
B --> BR["BronXatosi"]
B --> TO["TolovXatosi"]
B --> TP["TopilmadiXatosi"]Chap shox — bizniki, hammasi BahorXatosi dan. O'ng shox — JavaScript'ning o'z xatolari, ular bug haqida gapiradi. Kodda:
class BahorXatosi extends Error {
constructor(xabar, sozlama) {
super(xabar, sozlama);
this.name = "BahorXatosi";
this.kod = sozlama?.kod ?? "NOMALUM";
}
}
class BronXatosi extends BahorXatosi {
constructor(xabar, sozlama) {
super(xabar, sozlama);
this.name = "BronXatosi";
}
}
class TopilmadiXatosi extends BahorXatosi {
constructor(nima) {
super(`${nima} topilmadi`, { kod: "TOPILMADI" });
this.name = "TopilmadiXatosi";
}
}
const x = new TopilmadiXatosi("12-stol");
console.log(String(x)); // TopilmadiXatosi: 12-stol topilmadi
console.log(x.kod); // TOPILMADI
console.log(x instanceof BahorXatosi); // true
console.log(new TypeError("x") instanceof BahorXatosi); // falsekod faqat BahorXatosi da yozilgan — bolalar uni meros oladi. TopilmadiXatosi konstruktori boshqacha: u xabarni o'zi yasaydi, chaqiruvchi faqat "nima topilmadi" ni beradi. Har bola klass o'ziga qulay konstruktor tanlashi mumkin — asosiysi, super ga xabar va sozlama yetib borsin.
Endi eng muhim tekshiruv bitta qator: xato instanceof BahorXatosi — "kutilgan, biz tashlagan xato". Aks holda — bug.
6.2 Qancha klass kerak?
Har xato uchun klass yaratish — ortiqcha. Har bir klass — yoziladigan, o'qiladigan va eslab qolinadigan kod. Oddiy qoida: yangi klass faqat catch uni boshqacha hal qilishi kerak bo'lsa.
- Bron xatolari formada ko'rsatiladi, to'lov xatolari esa boshqa oynada va boshqa tugma bilan — ikki klass mantiqli.
- "Odam ko'p" va "vaqt yopiq" — ikkalasi ham bron formasida ko'rsatiladi. Ikki klass kerak emas: bitta
BronXatosiva ikki xilkod.
Dizayn naqshlari darsidagi YAGNI tamoyili shu yerda ham ishlaydi: ierarxiyani "keyin kerak bo'lib qolar" deb chuqurlashtirmang. Ko'p loyihalarga bitta ota va 2–4 bola yetadi.
Tekshirib ko'ring:
catchdaxato instanceof ErrortekshiruviBahorXatosini bug'dan ajrata oladimi?
Javob
Yo'q. Hamma xato turlari — TypeError ham, BahorXatosi ham — Error ning bolasi. instanceof Error faqat "bu xato obyektimi, satr emasmi?" degan savolga javob beradi. "Biz tashlaganmi?" degan savolga — faqat o'z ota klassimiz.
6.3 Begona xatoni o'z turingizga o'rash
Bizning funksiyamiz ichida JavaScript'ning o'z xatosi chiqishi mumkin — masalan, bron matni JSON'dan o'qilganda SyntaxError. Uni qanday hal qilamiz: qayta tashlaymizmi yoki "bizniki" qilamizmi?
Savolga javob: bu xato kimning aybi? Agar sabab — tashqaridan kelgan buzuq matn bo'lsa, bu bug emas, kutilgan holat. Demak u bizning turimizga aylanishi kerak. Asl xato esa cause da qoladi (throw va Error):
class BronXatosi extends Error {
constructor(xabar, sozlama) {
super(xabar, sozlama);
this.name = "BronXatosi";
this.kod = sozlama?.kod ?? "NOMALUM";
}
}
function bronniOqi(matn) {
try {
return JSON.parse(matn);
} catch (xato) {
throw new BronXatosi("Bron matni buzilgan.", {
kod: "MATN_BUZUQ",
cause: xato,
});
}
}
try {
bronniOqi('{"ism": "Malika"');
} catch (xato) {
console.log(String(xato)); // BronXatosi: Bron matni buzilgan.
console.log(xato.kod, xato.cause.name); // MATN_BUZUQ SyntaxError
}Endi yuqoridagi catch bitta savol beradi: instanceof BronXatosi. U SyntaxError haqida bilishi shart emas — bu bronniOqi ning ichki ishi. Ertaga bron matni JSON emas, boshqa formatda kelsa, faqat bronniOqi o'zgaradi; uni chaqiruvchilar esa o'zgarmaydi.
Bu — chegara g'oyasi. Har funksiya yoki modulning "ichi" va "tashqi yuzi" bor. Ichkarida qanday kutubxona yoki format ishlatilganini tashqi kod bilmasin — tashqariga faqat sizning sohangizning xatolari chiqsin. Lekin ehtiyot bo'ling: faqat kutilgan sababni o'rang. try ichida bug bo'lishi mumkin bo'lgan kod ko'p bo'lsa, uni ham "bron matni buzilgan" deb o'rab, yashirib qo'yasiz. Shuning uchun bu yerda ham try ichida faqat bitta qator — JSON.parse.
Tekshirib ko'ring:
bronniOqidagitrygareturn JSON.parse(matn).ism.toUpperCase();yozilsa va matndaismbo'lmasa, qanday xato chiqadi?
Javob
BronXatosi: Bron matni buzilgan. — va bu yolg'on. Matn to'g'ri JSON, unda shunchaki ism yo'q; toUpperCase dan TypeError chiqdi va catch uni ham o'radi. To'g'ri yo'l: try da faqat JSON.parse, tuzilma tekshiruvi esa alohida, o'z throw lari bilan — «Vazifalar qadami» dagi paketniOqi kabi.
7. Brauzerda: maydonni ko'rsatadigan xato
Bron formasi endi BronXatosi ning maydon ini ishlatadi: noto'g'ri maydon qizil bo'ladi va fokus aynan unga o'tadi. Pastdagi «Bug'ni sinash» tugmasi kod ichidagi xatoni taqlid qiladi:
<style>
body { margin: 1rem; font: 1rem/1.5 system-ui, sans-serif; }
input, button { font: inherit; min-height: 2.75rem; }
[aria-invalid="true"] { outline: 3px solid #b3261e; }
#javob { min-height: 1.5em; font-weight: bold; }
</style>
<form id="bron" novalidate>
<label for="odam">Necha kishi?</label>
<input id="odam" name="odam" type="number" value="25">
<label for="vaqt">Soat</label>
<input id="vaqt" name="vaqt" type="time" value="19:00">
<button>Bron qilish</button>
</form>
<p id="javob" aria-live="polite"></p>
<button type="button" id="bug">Bug'ni sinash</button>
<script>
class BronXatosi extends Error {
constructor(xabar, sozlama) {
super(xabar, sozlama);
this.name = "BronXatosi";
this.maydon = sozlama?.maydon;
}
}
function bronniTekshir(odam, vaqt) {
if (!(odam >= 1 && odam <= 20)) {
throw new BronXatosi("1–20 kishi.", { maydon: "odam" });
}
if (vaqt < "10:00" || vaqt > "22:00") {
throw new BronXatosi("Soat 10:00–22:00.", { maydon: "vaqt" });
}
}
const forma = document.getElementById("bron");
const javob = document.getElementById("javob");
let buzuqmi = false;
forma.addEventListener("submit", (event) => {
event.preventDefault();
forma.odam.removeAttribute("aria-invalid");
forma.vaqt.removeAttribute("aria-invalid");
try {
if (buzuqmi) {
null.odam; // ataylab bug
}
bronniTekshir(Number(forma.odam.value), forma.vaqt.value);
javob.textContent = "Bron qabul qilindi.";
} catch (xato) {
if (!(xato instanceof BronXatosi)) {
javob.textContent = "Kutilmagan xato. Keyinroq urining.";
throw xato;
}
javob.textContent = xato.message;
const maydon = forma[xato.maydon];
maydon.setAttribute("aria-invalid", "true");
maydon.focus();
}
});
document.getElementById("bug").addEventListener("click", () => {
buzuqmi = true;
forma.requestSubmit();
});
</script>Sinab ko'ring:
- «Bron qilish» — "1–20 kishi.", odam maydoni qizil, fokus unda. 4 ni yozing va soatni 23:00 qiling — endi vaqt maydoni qizil.
- To'g'ri qiymatlar bilan — "Bron qabul qilindi.".
- «Bug'ni sinash» — ekranda umumiy "Kutilmagan xato…", konsolda esa
Uncaught TypeError: Cannot read properties of null (reading 'odam'). Foydalanuvchiga ichki matn ko'rinmadi, dasturchi esa bug'ni to'liq ko'radi.
forma[xato.maydon] — formaning name atributi bo'yicha maydoni (Forma qiymatlarini o'qish). xato.maydon — "odam" yoki "vaqt", ya'ni xato o'zi "meni qayerga ko'rsating" deydi. requestSubmit() — formani tugma bosilgandek yuboradi, submit hodisasi bilan.
Begona xato uchun nima qilinganiga e'tibor bering: foydalanuvchiga umumiy xabar va qayta tashlash. Bu ikkisi bir-biriga zid emas — biri odam uchun, biri dasturchi uchun. Bu qarorni keyingi darsda strategiya darajasiga ko'taramiz.
8. Ko'p uchraydigan xatolar
8.1 name unutilgan
class TolovXatosi extends Error {} — konsolda Error: …. Tuzatish: konstruktorda this.name = "TolovXatosi".
8.2 super dan oldin this
class BronXatosi extends Error {
constructor(xabar) {
this.name = "BronXatosi";
super(xabar);
}
}
new BronXatosi("stol band");ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructorTarjimasi: "meros olgan klassda this ga murojaat qilishdan yoki konstruktordan qaytishdan oldin super konstruktorini chaqirish shart". Xato obyekti super ichida — Error da — yaratiladi; undan oldin this hali yo'q (Meros). Tuzatish: super(...) — birinchi qator.
8.3 sozlama super ga berilmagan
class BronXatosi extends Error {
constructor(xabar, sozlama) {
super(xabar);
this.name = "BronXatosi";
}
}
const asl = new SyntaxError("buzuq JSON");
const xato = new BronXatosi("Bron o'qilmadi", { cause: asl });
console.log(xato.cause); // undefinedcause jimgina yo'qoldi — Error uni hech qachon ko'rmadi. Tuzatish: super(xabar, sozlama).
8.4 Ota klass bolasidan oldin tekshiriladi
«Tartib: avval bola, keyin ota» bo'limi: bola uchun shox hech qachon ishlamaydi. Tuzatish: aniq klassni oldin tekshiring.
8.5 message ni solishtirish
if (xato.message.includes("20 kishi")) — matn o'zgarsa, shart buziladi. Tuzatish: instanceof va kod.
9. Mashqlar
1-mashq (oson): TolovXatosi
TolovXatosi klassini yozing: name — "TolovXatosi", qo'shimcha maydon summa. Konstruktor (xabar, summa) oladi. new TolovXatosi("Mablag' yetarli emas", 73000) ni yaratib, String(xato), xato.summa va xato instanceof Error ni chiqaring.
Yechim
class TolovXatosi extends Error {
constructor(xabar, summa) {
super(xabar);
this.name = "TolovXatosi";
this.summa = summa;
}
}
const xato = new TolovXatosi("Mablag' yetarli emas", 73000);
console.log(String(xato)); // TolovXatosi: Mablag' yetarli emas
console.log(xato.summa); // 73000
console.log(xato instanceof Error); // trueKonstruktor imzosi — sizning qaroringiz: bu yerda ikkinchi argument sozlama emas, summa. cause kerak bo'lsa, uchinchi parametr qo'shib, super(xabar, sozlama) ga bering.
2-mashq (o'rta): To'g'ri tartib
Quyidagi catch kodi bron xatosini "umumiy" xabar bilan ko'rsatyapti. Tuzating va uch xato bilan sinang: BronXatosi, BahorXatosi, TypeError. Ishora: «Tartib: avval bola, keyin ota».
function xabarYasa(xato) {
if (xato instanceof BahorXatosi) {
return "Bahor: " + xato.message;
}
if (xato instanceof BronXatosi) {
return "Bron: " + xato.message;
}
throw xato;
}Yechim
class BahorXatosi extends Error {
constructor(xabar) {
super(xabar);
this.name = "BahorXatosi";
}
}
class BronXatosi extends BahorXatosi {
constructor(xabar) {
super(xabar);
this.name = "BronXatosi";
}
}
function xabarYasa(xato) {
if (xato instanceof BronXatosi) {
return "Bron: " + xato.message;
}
if (xato instanceof BahorXatosi) {
return "Bahor: " + xato.message;
}
throw xato;
}
const xatolar = [
new BronXatosi("stol band"),
new BahorXatosi("menyu yopiq"),
new TypeError("x is not a function"),
];
for (const x of xatolar) {
try {
console.log(xabarYasa(x));
} catch (begona) {
console.log("Qayta tashlandi:", String(begona));
}
}Konsolda:
Bron: stol band
Bahor: menyu yopiq
Qayta tashlandi: TypeError: x is not a functionIkki if o'rni almashdi, xolos. Endi bola klass birinchi tekshiriladi, ota esa "qolgan hamma bizniki" vazifasini bajaradi.
3-mashq (qiyin): Kod bo'yicha xabar
BronXatosi da kod bor (ODAM_KOP, VAQT_YOPIQ, STOL_BAND). Ingliz tilidagi mehmonlar uchun ham xabar kerak. xabarniTarjimaQil(xato, til) funksiyasini yozing: xabarlar lug'atidan kod va til bo'yicha matn olsin. Lug'atda kod yo'q bo'lsa — xato.message ni qaytarsin. BronXatosi bo'lmagan xatoni qayta tashlasin. Lug'atdan o'qishda Object.hasOwn ishlating (Prototype pollution darsidagi odat).
const xabarlar = {
ODAM_KOP: { uz: "20 kishigacha.", en: "Up to 20 guests." },
VAQT_YOPIQ: { uz: "Soat 10:00–22:00.", en: "10:00–22:00 only." },
};Yechim
class BronXatosi extends Error {
constructor(xabar, sozlama) {
super(xabar, sozlama);
this.name = "BronXatosi";
this.kod = sozlama?.kod ?? "NOMALUM";
}
}
const xabarlar = {
ODAM_KOP: { uz: "20 kishigacha.", en: "Up to 20 guests." },
VAQT_YOPIQ: { uz: "Soat 10:00–22:00.", en: "10:00–22:00 only." },
};
function xabarniTarjimaQil(xato, til) {
if (!(xato instanceof BronXatosi)) {
throw xato;
}
if (!Object.hasOwn(xabarlar, xato.kod)) {
return xato.message;
}
return xabarlar[xato.kod][til];
}
const odamKop = new BronXatosi("Ko'p odam", { kod: "ODAM_KOP" });
const band = new BronXatosi("Stol band", { kod: "STOL_BAND" });
console.log(xabarniTarjimaQil(odamKop, "en")); // Up to 20 guests.
console.log(xabarniTarjimaQil(odamKop, "uz")); // 20 kishigacha.
console.log(xabarniTarjimaQil(band, "en")); // Stol bandkod — barqaror kalit: tarjimalar lug'ati unga tayanadi, message esa zaxira. Nega Object.hasOwn? Kod "toString" bo'lib qolsa, xabarlar["toString"] meros funksiyani topardi va [til] — undefined qaytarardi. hasOwn faqat lug'atning o'z kalitlarini ko'radi. Yana bir yaxshilash: til uchun matn yo'q bo'lsa ("ru"), ?? xato.message bilan zaxiraga qayting.
4-mashq: Vazifalar qadami — VazifaXatosi
feature/import branch'ida davom etamiz. O'tgan darsda ko'rdik: import tinglovchisidagi catch buzilgan VazifalarRoyxati.dan ning xabarini ham maydon yoniga yozdi. Endi o'z xato turimizni kiritamiz.
VazifaXatosi extends Errorklassi:name—"VazifaXatosi",kodmaydoni (sozlama?.kod, bo'lmasa"NOMALUM"). Uni faylning boshiga,VazifavaVazifalarRoyxatiyoniga qo'ying.paketniOqidagi to'rtthrow new Error—VazifaXatosiga, kodlari bilan:JSON,TUZILMA,VERSIYA.- Tinglovchidagi
catchfaqatVazifaXatosini ko'rsatsin, qolganini qayta tashlasin.
Yechim
Faylning boshida, VazifalarRoyxati dan keyin:
class VazifaXatosi extends Error {
constructor(xabar, sozlama) {
super(xabar, sozlama);
this.name = "VazifaXatosi";
this.kod = sozlama?.kod ?? "NOMALUM";
}
}paketniOqi:
function paketniOqi(matn) {
let xom;
try {
xom = JSON.parse(matn);
} catch (xato) {
throw new VazifaXatosi(
"Matn JSON emas. Eksportni to'liq oling.",
{ kod: "JSON", cause: xato },
);
}
if (!oddiyObyektmi(xom)) {
throw new VazifaXatosi("Bu matn vazifalar eksporti emas.", {
kod: "TUZILMA",
});
}
const paket = xavfsizBirlashtir({}, xom);
if (paket.versiya !== 1) {
throw new VazifaXatosi(
`Versiya ${paket.versiya} o'qilmaydi — faqat 1.`,
{ kod: "VERSIYA" },
);
}
if (!Array.isArray(paket.vazifalar)) {
throw new VazifaXatosi("Matnda vazifalar ro'yxati yo'q.", {
kod: "TUZILMA",
});
}
return paket.vazifalar.map(vazifaniOl);
}Tinglovchi:
importTugma.addEventListener("click", () => {
importXatosiniTozala();
elonQil("");
try {
const malumotlar = paketniOqi(importMatn.value);
royxatniAlmashtir(malumotlar);
elonQil(`${malumotlar.length} ta vazifa import qilindi.`);
} catch (xato) {
if (!(xato instanceof VazifaXatosi)) {
throw xato;
}
importXatosiniKorsat(xato.message);
}
});Nimaga e'tibor bering:
- Klass fayl boshida.
classe'lonlari TDZ'ga tushadi (TDZ) —Vazifakabi, uni ishlatadigan koddan oldin turishi kerak. Bu yerdapaketniOqifaqat bosishda chaqiriladi, lekin tartib qoidasi bitta: klasslar — boshida. causehamon bor.{ kod: "JSON", cause: xato }—superikkalasini ham oladi:causeniErroryozadi,kodni biz.- Kodlar hozircha faqat ma'lumot. Ekran ularni ishlatmaydi. Lekin ertaga "versiya eskirgan — mana yangilash yo'riqnomasi" kabi maxsus javob kerak bo'lsa,
xato.kod === "VERSIYA"tayyor turibdi.
Node'da — to'rt holat va bitta "bug":
class VazifaXatosi extends Error {
constructor(xabar, sozlama) {
super(xabar, sozlama);
this.name = "VazifaXatosi";
this.kod = sozlama?.kod ?? "NOMALUM";
}
}
function paketniOqi(matn) {
let xom;
try {
xom = JSON.parse(matn);
} catch (xato) {
const sozlama = { kod: "JSON", cause: xato };
throw new VazifaXatosi("Matn JSON emas.", sozlama);
}
if (xom?.versiya !== 1) {
throw new VazifaXatosi("Versiya mos emas.", { kod: "VERSIYA" });
}
return xom.vazifalar.map((v) => v.matn.trim());
}
const matnlar = [
'{"versiya": 1, "vazifalar": [{"matn": " Choy "}]}',
"{",
'{"versiya": 2}',
'{"versiya": 1, "vazifalar": [{"id": 1}]}',
];
for (const matn of matnlar) {
try {
console.log("O'qildi:", paketniOqi(matn));
} catch (xato) {
if (xato instanceof VazifaXatosi) {
console.log(`Foydalanuvchiga: ${xato.message} [${xato.kod}]`);
} else {
console.log(`BUG: ${xato.name}: ${xato.message}`);
}
}
}Konsolda:
O'qildi: [ 'Choy' ]
Foydalanuvchiga: Matn JSON emas. [JSON]
Foydalanuvchiga: Versiya mos emas. [VERSIYA]
BUG: TypeError: Cannot read properties of undefined (reading 'trim')To'rtinchi matnda matn yo'q, v.matn.trim() esa — TypeError. Bu tekshiruvsiz qolgan joy, ya'ni bug, va endi u aniq ajratildi: foydalanuvchi xatosi bilan aralashmadi. (Bu qisqartirilgan sinov nusxasi — ilovadagi paketniOqi da trim yo'q.)
Brauzerda sinab ko'ring (Chrome 154 da tekshirilgan):
- Buzuq JSON,
versiya: 2,null, to'g'ri eksport,__proto__li paket — avvalgidek. - DevTools'da
VazifalarRoyxati.danni yana buzing (o'tgan darsdagi parcha) va import qiling. Endi konsolda qizilUncaught TypeError: sinov: dasturchi xatosi— bug ko'rindi. Maydon yonida esa xabar yo'q. Bug ko'rinmas emas, lekin foydalanuvchi uchun tugma "hech narsa qilmadi". Unga ham bir so'z kerak — keyingi darsda.
Commit: Vazifalar: import xatolari uchun VazifaXatosi klassi.
10. Real ishda
- Node'ning o'zi. Node xatolarida
codemaydoni bor:ENOENT,ERR_INVALID_ARG_TYPE,ECONNREFUSED. Hujjatda har kod tavsiflangan — ularni Google'da qidirish oson. Sizningkodlaringiz ham shu g'oya. - Backend freymvorklari. NestJS'da
NotFoundException,BadRequestException—Errordan meros olgan klasslar, ichida HTTP status. Siz tashlaysiz, freymvork ushlab, to'g'ri javob qaytaradi. Express'da bunday klasslarni o'zingiz yozasiz — aynan bugungiBahorXatosikabi. - Kutubxonalar. Ma'lumotlar bazasi drayverlari
DatabaseError, tekshiruv kutubxonalariValidationErrortashlaydi. Ularniinstanceofbilan ajratib, foydalanuvchiga tushunarli xabar berasiz. - Intervyu. "Custom error qanday yaratiladi?", "nega
nameni qo'yish kerak?", "xatolarnimessagebo'yicha ajratish nega yomon?" — ko'p uchraydi.
Xulosa
- O'z xato turi:
class X extends Error, konstruktordasuper(xabar, sozlama)— birinchi, keyinthis.name = "X". namesiz xato konsoldaError:bo'lib chiqadi;new.target.namequlay, lekin siqilgan kodda nom o'zgarishi mumkin.kod— kod uchun barqaror sabab,message— odam uchun matn;messageni solishtirmang.catchdainstanceofbilan ajrating: avval bola, keyin ota; notanish xatoni qayta tashlang.- Umumiy ota klass (
BahorXatosi) "bizning xatomizmi?" savoliga bitta javob beradi; yangi klass — faqat boshqacha hal qilinsa.
Keyingi dars: Xato strategiyasi — xatoni qayerda ushlash, foydalanuvchiga nima ko'rsatish va nimani logga yozish; operatsion xatolar va bug'lar, "tez yiqil" tamoyili.
Manbalar
- MDN: "Error — Custom error types", "extends", "new.target" — developer.mozilla.org
- Node.js: "Errors — error.code" — nodejs.org/api/errors.html
- ECMAScript 2025 Language Specification: "Error Objects", "NativeError Object Structure" — tc39.es/ecma262
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!