Mundarija (32)
- Bu darsda
- 1. Nega bu kerak?
- 2. throw: o'yinni to'xtatish
- 2.1 Birinchi throw
- 2.2 return va throw
- 2.3 throw dan keyin yangi qator yo'q
- 3. Error obyekti
- 3.1 Uch xususiyat
- 3.2 stack qachon yoziladi
- 3.3 Qaysi turni tashlash
- 4. Satr tashlamang
- 4.1 Ishlaydi, lekin...
- 4.2 Qoida
- 5. cause: sabablar zanjiri
- 5.1 Xatoni o'rash
- 5.2 Zanjirni oxirigacha o'qish
- 6. Error.isError: haqiqiy xatomi?
- 7. Brauzerda: bron formasi
- 8. Ko'p uchraydigan xatolar
- 8.1 Satr tashlash
- 8.2 O'rashda sababni yo'qotish
- 8.3 Foydalanuvchiga stack ko'rsatish
- 8.4 throw dan keyin yangi qator
- 8.5 Odatiy natija uchun throw
- 9. Mashqlar
- 1-mashq (oson): Narx tekshiruvi
- 2-mashq (o'rta): Setter xato tashlasin
- 3-mashq (qiyin): Sabablar zanjiri
- 4-mashq: Vazifalar qadami — jim xatolarni ochiq qilish
- 10. Real ishda
- Xulosa
- Manbalar
JavaScript throw va Error obyekti: o'zingiz xato tashlash, stack va cause
Qisqacha:
throw new Error("sabab")— o'z qoidangiz buzilganda xato tashlash: funksiya shu zahoti to'xtaydi, xato esa birinchicatchgacha ko'tariladi. DoimErrorobyektini tashlang (yokiTypeError,RangeError): undamessage,nameva qayerda yaratilganini ko'rsatadiganstackbor. Past darajadagi xatoni o'rab, yangi xato tashlasangiz, aslini{ cause: xato }bilan bog'lang — sabab yo'qolmaydi.
Bu darsda
throwbilan o'z qoidangiz buzilganini bildira olasiz vareturndan farqini tushuntira olasiz.Errorobyektiningmessage,namevastackxususiyatlarini o'qiysiz va to'g'ri xato turini tanlaysiz.- Satr yoki oddiy obyekt tashlash nega xavfli ekanini ko'rasiz.
causebilan sabablar zanjirini yasaysiz va uni oxirigacha o'qiysiz.Error.isError(ES2026) nima uchun kerakligini bilasiz.vazifalarimportidagi jim xatolarnithrowbilan ochiq xatoga aylantirasiz.
Oldin bilishingiz kerak: try / catch / finally, Stack trace va xato turlari, Konstruktor funksiya va new, Getter/setter va static.
1. Nega bu kerak?
O'tgan darsda JavaScript'ning o'zi tashlaydigan xatolarni ushladik: JSON.parse buzuq matnni ko'rsa — SyntaxError, null dan xususiyat o'qilsa — TypeError. Lekin ko'p xatolar JavaScript uchun xato emas. Ular bizning qoidamiz buzilganda paydo bo'ladi.
«Bahor»da bron ko'pi bilan 20 kishiga qabul qilinadi. Kimdir 25 kishilik bron yubordi. JavaScript uchun 25 — oddiy son, u hech qanday xato bermaydi. Bu qoida faqat bizning boshimizda. Uni qanday qilib "qizil xato" darajasida bildiramiz?
Oldingi darslarda ikki yo'lni sinagan edik, ikkalasi ham chala:
- Getter/setter darsida noto'g'ri narx
console.warnbilan bildirildi. Ogohlantirish chiqdi, lekin dastur hech narsa bo'lmagandek davom etdi — noto'g'ri qiymat bilan. vazifalarimportidapaketniOqinoto'g'ri versiyani ko'rib,[]qaytardi. Natija — ro'yxat jimgina bo'shab qoldi. Bo'sh eksport bilan buzuq eksportni ajratib bo'lmadi.
Maxsus qiymat qaytarish (null, false, []) chaqiruvchini "tekshirishni unutmaslikka" majbur qiladi. Unutsa — xato jimgina oldinga o'tib ketadi. Bizga JavaScript'ning o'z xatolaridek ishlaydigan narsa kerak: e'tiborsiz qoldirib bo'lmaydigan, ushlanmasa — dasturni to'xtatadigan. Bu — throw.
Hayotdan o'xshatish: futboldagi hakam hushtagi. O'yinchi qoidani buzdi — hakam hushtak chaladi va o'yin shu zahoti to'xtaydi. Hech kim "hushtakni eshitmadim" deb davom eta olmaydi. Keyin nima qilishni — jarima yoki ogohlantirish — boshqa odam hal qiladi. throw — hushtak, catch — qaror qabul qiladigan joy.
2. throw: o'yinni to'xtatish
2.1 Birinchi throw
function bronQil(odam) {
if (odam > 20) {
throw new RangeError(`Bron ko'pi bilan 20 kishiga: ${odam}`);
}
return `${odam} kishilik stol tayyor`;
}
try {
console.log(bronQil(4));
console.log(bronQil(25));
console.log("Bu qator ishlamaydi");
} catch (xato) {
console.log("Rad etildi:", xato.message);
}Konsolda:
4 kishilik stol tayyor
Rad etildi: Bron ko'pi bilan 20 kishiga: 25throw ifoda; — ko'rsatma: "shu qiymatni xato sifatida tashla". Undan keyin uch narsa bo'ladi:
- Funksiya shu zahoti to'xtaydi —
returnga yetib bormaydi. - Xato o'tgan darsdagidek chaqiruvlar steki bo'ylab birinchi
catchgacha ko'tariladi. tryning qolgan qatorlari ham tashlanadi — "Bu qator ishlamaydi" chiqmadi.
Ya'ni o'zimiz tashlagan xato JavaScript'ning JSON.parse dagi xatosidan hech farq qilmaydi. catch uni xuddi shunday ushlaydi.
try siz-chi? Xato Uncaught bo'ladi. bron.js faylida xuddi shu funksiya va ostida ikki qator bor: console.log(bronQil(4)); va console.log(bronQil(25));. node bron.js (fayl kurs/mashqlar/10/ da, yo'l qisqartirildi):
C:\...\10\bron.js:3
throw new RangeError(`Bron ko'pi bilan 20 kishiga: ${odam}`);
^
RangeError: Bron ko'pi bilan 20 kishiga: 25
at bronQil (C:\...\10\bron.js:3:11)
at Object.<anonymous> (C:\...\10\bron.js:8:13)
at Module._compile (node:internal/modules/cjs/loader:1929:14)(node:internal qatorlari qisqartirildi.) Tanish ko'rinish: Stack trace darsidagi xabarlar bilan bir xil — tur, matn, at qatorlari. Endi faqat matnni biz yozdik.
2.2 return va throw
Ikkalasi ham funksiyani to'xtatadi. Farqi — natija qayerga boradi:
return qiymat |
throw xato |
|
|---|---|---|
| Qayerga | Chaqirgan joyga, bitta qavat | Birinchi catch gacha, kerak bo'lsa ko'p qavat |
| Ma'nosi | "Ish bajarildi, mana natija" | "Ish bajarilmadi, mana sabab" |
| E'tiborsiz qoldirsa | Qiymat jimgina yo'qoladi | Dastur to'xtaydi (Uncaught) |
| Qachon | Odatiy natija | Funksiya o'z vazifasini bajara olmadi |
Oxirgi qator — eng muhim qaror. "Topilmadi" har doim ham xato emas: find topmasa undefined qaytaradi, chunki "yo'q" — odatiy javob. Bron qoidasining buzilishi esa — funksiya va'da qilgan ishini bajara olmadi. Shunday paytda throw.
2.3 throw dan keyin yangi qator yo'q
function tekshir(odam) {
throw
new RangeError("Ko'p odam");
}SyntaxError: Illegal newline after throwTarjimasi: "throw dan keyin yangi qator — noqonuniy". return dan keyingi yangi qator undefined qaytaradi (return va erta qaytish). throw da JavaScript bunga yo'l qo'ymaydi: "nimani tashlash kerak?" — noma'lum. Tashlanadigan qiymat throw bilan bir qatorda boshlansin.
Tekshirib ko'ring:
bronQil(25)trysiz chaqirildi.bronQildan keyingi qatorlar bajariladimi?
Javob
Node'da — yo'q: ushlanmagan xato butun dasturni to'xtatadi. Brauzerda — faqat joriy ish (masalan, shu hodisa tinglovchisi) to'xtaydi, sahifa yashashda davom etadi (Stack trace darsidagi farq).
3. Error obyekti
3.1 Uch xususiyat
new Error("matn") — oddiy klass nusxasi (class sintaksisi). Unda uchta muhim xususiyat bor:
const xato = new Error("Stol band");
console.log(xato.message); // Stol band
console.log(xato.name); // Error
console.log(typeof xato.stack); // string
console.log(xato.stack.split("\n")[0]); // Error: Stol band
console.log(String(xato)); // Error: Stol bandmessage— siz bergan matn.name— xato turi.Erroruchun"Error",RangeErroruchun"RangeError". Umessagedan oldin, ikki nuqta bilan chiqadi.stack— matn: birinchi qatoriname: message, keyinat …qatorlari — Stack trace darsida o'qigan izning o'zi.
stack — ECMAScript standartida hali yo'q xususiyat, lekin hamma brauzer va Node'da bor. Uni standartga kiritish taklifi TC39'da ko'rib chiqilmoqda. Formatlari biroz farq qiladi: Chrome va Node — at funksiya (fayl:qator:ustun), Firefox — funksiya@fayl:qator:ustun. Shuning uchun stack ni o'qish uchun ishlating — odam yoki xato monitoringi xizmati o'qisin. Uning ichidan kod bilan qiymat qirqib olishga urinmang.
new siz Error("matn") ham xuddi shu obyektni yaratadi — Error new.target ni o'zi tekshiradi. Lekin kodda doim new Error yozing: o'qigan odam darhol "bu yerda obyekt yaratilyapti" deb tushunadi.
3.2 stack qachon yoziladi
Qiziq va foydali detal: stack xato yaratilgan paytda olinadi, tashlangan paytda emas.
function xatoYasa() {
return new Error("Qayerda yaratildi?");
}
function tashla() {
throw xatoYasa();
}
try {
tashla();
} catch (xato) {
const birinchiQator = xato.stack.split("\n")[1].trim();
console.log(birinchiQator.split(" ")[1]); // xatoYasa
}catch dagi ikki qator stack matnidan funksiya nomini qirqib oladi (faqat shu tajriba uchun — real kodda bunday qilmang, sababi yuqorida). Avval split("\n")[1] ikkinchi qatorni oladi — bu birinchi at … qatori. Keyin trim() boshidagi bo'sh joylarni olib tashlaydi. Oxirida split(" ")[1] — at dan keyingi so'z.
Izning birinchi at qatori — xatoYasa, ya'ni new Error yozilgan joy. Xato tashlangan tashla undan keyin keladi. Odatda bu farq sezilmaydi, chunki throw new Error(...) bitta qatorda yoziladi. Lekin xatoni oldindan yaratib qo'yib, keyin tashlasangiz, iz noto'g'ri joyni ko'rsatadi. Qoida: xatoni tashlanadigan joyda yarating.
3.3 Qaysi turni tashlash
Stack trace darsidagi xato turlari — hammasi klass, ularni o'zingiz ham yaratasiz. Turni ma'nosiga qarab tanlang:
| Vaziyat | Tur | Misol |
|---|---|---|
| Qiymat ruxsat etilgan oraliqdan tashqarida | RangeError |
25 kishilik bron, manfiy narx |
| Qiymatning turi noto'g'ri | TypeError |
narx o'rniga satr, new siz chaqiruv |
| Boshqa har qanday qoida buzildi | Error |
stol band, menyu yopiq |
SyntaxError, ReferenceError ni o'zingiz tashlamang — ular JavaScript'ning o'z kodi va JSON kabi formatlar uchun. O'z sohangizdagi xato turlari ("bron xatosi", "to'lov xatosi") — O'z xato klasslaringiz darsida.
Konstruktor funksiya va new darsida new.target bilan new siz chaqiruvni "tuzatgan" edik va xato tashlash mumkinligini aytgan edik. Mana u — TypeError bilan:
function Taom(nom) {
if (!new.target) {
throw new TypeError("Taom ni new bilan chaqiring");
}
this.nom = nom;
}
try {
Taom("Osh");
} catch (xato) {
console.log(String(xato)); // TypeError: Taom ni new bilan chaqiring
}
console.log(new Taom("Osh").nom); // OshKlasslar ham new siz chaqirilsa aynan shunday — TypeError — tashlaydi (class sintaksisi). Biz JavaScript'ning o'z xulqini takrorladik.
Tekshirib ko'ring: Funksiya narxni oladi.
narxniQoy("35000")vanarxniQoy(-5)uchun qaysi xato turlari mos?
Javob
"35000" — satr, ya'ni turi noto'g'ri: TypeError. -5 — son, turi to'g'ri, lekin qiymati ruxsat etilgan oraliqda emas: RangeError. Tur xabarni o'qigan dasturchiga qayerdan qidirishni darhol aytadi.
4. Satr tashlamang
4.1 Ishlaydi, lekin...
throw istalgan qiymatni tashlay oladi — satr, son, obyekt:
try {
throw "Bron 20 kishidan oshmasin";
} catch (xato) {
console.log(typeof xato); // string
console.log(xato.message); // undefined
console.log(xato.stack); // undefined
}catch satrni oldi. Lekin endi xato.message yo'q — catch ichidagi xato.message ni ishlatadigan har qanday kod undefined ko'rsatadi. stack ham yo'q: xato qayerdan kelgani noma'lum. Ushlanmasa, Node shunday deydi:
C:\...\10\satr.js:1
throw "Bron 20 kishidan oshmasin";
^
Bron 20 kishidan oshmasin
(Use `node --trace-uncaught ...` to show where the exception was thrown)Na tur, na at qatorlari. Node o'zi "qayerda tashlanganini ko'rish uchun maxsus bayroq bilan ishga tushiring" deb maslahat beryapti. Bitta faylda bu chidasa bo'ladi. Yuz faylli loyihada — satr qayerdan uchganini topish soatlab vaqt oladi.
Oddiy obyekt (throw { kod: 404 }) ham shunday: message ham, stack ham yo'q.
4.2 Qoida
Faqat Error (yoki uning bolasini) tashlang. Uch sabab:
stack— xato qayerdan kelgani.- Har
catchxato.messagevaxato.namega tayanishi mumkin. - Kutubxonalar, xato monitoringi xizmatlari va DevTools
Errorni alohida ko'rsatadi.
Kod sifatini tekshiruvchi vositalarda buning uchun qoida bor — ESLint'dagi no-throw-literal (ESLint'ni 12-qismda o'rganamiz).
5. cause: sabablar zanjiri
5.1 Xatoni o'rash
Bronlar ro'yxati matndan o'qiladi. Buzuq bo'lsa, JSON.parse SyntaxError tashlaydi — lekin "1:30 da , kutilgan edi" degan xabar yuqoridagi kodga hech narsa demaydi. Yuqoriga ma'noli xato kerak: "bronlar ro'yxati o'qilmadi". Ammo asl sababni ham yo'qotmaslik kerak — dasturchiga u kerak bo'ladi.
Stack trace darsida Node'ning fetch failed xatosini o'qigan edik: uning [cause] qismida asl sabab turardi. O'zimiz ham shunday qilamiz. Error ning ikkinchi argumenti — sozlamalar obyekti, uning cause maydoni:
function bronlarniOqi(matn) {
try {
return JSON.parse(matn);
} catch (xato) {
throw new Error("Bronlar ro'yxati o'qilmadi", { cause: xato });
}
}
try {
bronlarniOqi('[{"ism": "Malika", "odam": 2}');
} catch (xato) {
console.log(xato.message);
console.log(xato.cause.name);
console.log(xato.cause.message);
}Konsolda:
Bronlar ro'yxati o'qilmadi
SyntaxError
Expected ',' or ']' after array element in JSON at position 29 (line 1 column 30)Yuqoridagi kod oddiy, tushunarli xabarni oldi. Ichkarida esa asl SyntaxError — turi, matni va o'z stack i bilan — saqlanib qoldi. cause — "sabab": ES2022 da qo'shilgan; Baseline ma'lumotiga ko'ra 2021-yil sentabrdan barcha asosiy brauzerlarda bor, 2024-yil martdan esa keng qo'llab-quvvatlanadi.
Ushlanmasa, Node ikkalasini ham ko'rsatadi. bronlar.js da — bronlarniOqi va uning try siz bitta chaqiruvi:
Error: Bronlar ro'yxati o'qilmadi
at bronlarniOqi (C:\...\10\bronlar.js:5:11)
at Object.<anonymous> (C:\...\10\bronlar.js:9:1)
... 6 lines matching cause stack trace ...
at node:internal/main/run_main_module:33:47 {
[cause]: SyntaxError: Expected ',' or ']' after array element in JSON at position 29 (line 1 column 30)
at JSON.parse (<anonymous>)
at bronlarniOqi (C:\...\10\bronlar.js:3:17)
at Object.<anonymous> (C:\...\10\bronlar.js:9:1)
}([cause] ostidagi node:internal qatorlari qisqartirildi.) ... 6 lines matching cause stack trace ... — "6 qator sabab izi bilan bir xil": Node takrorni qisqartirdi. O'qish tartibi — Stack trace darsidagidek: tashqi xato "nima buzildi", ichkisi "nega".
Sxemada — zanjir. Har o'q "sababi":
flowchart LR
A["Error: Bronlar ro'yxati o'qilmadi"] -- "cause" --> B["SyntaxError: Expected ',' or ']'"]5.2 Zanjirni oxirigacha o'qish
Zanjir uzun bo'lishi mumkin: har qavat o'z ma'nosini qo'shadi. Uni sikl bilan aylanamiz:
const ichki = new SyntaxError("29-o'rinda ',' kutilgan edi");
const orta = new Error("Bronlar o'qilmadi", { cause: ichki });
const tashqi = new Error("Hisobot tayyorlanmadi", { cause: orta });
let joriy = tashqi;
while (joriy) {
console.log(`${joriy.name}: ${joriy.message}`);
joriy = joriy.cause;
}Konsolda:
Error: Hisobot tayyorlanmadi
Error: Bronlar o'qilmadi
SyntaxError: 29-o'rinda ',' kutilgan ediichki da cause yo'q — undefined, sikl to'xtaydi (while). Eng pastdagi qator — ildiz sabab.
Uchta detal:
causefaqat sozlamada berilganda paydo bo'ladi.new Error("x")da u umuman yo'q ("cause" in xato—false). Ehtiyot bo'ling:{ cause: undefined }yozsangiz, xususiyat paydo bo'ladi, qiymatiundefined.cause— sanalmaydigan xususiyat (Xususiyat deskriptorlari):Object.keys(xato)uni ko'rsatmaydi.causega istalgan qiymat berish mumkin, lekin odatda ushlangan xatoning o'zi beriladi.
Tekshirib ko'ring:
catch (xato) { throw new Error("Bron saqlanmadi"); }— bu kodda nima yo'qoladi?
Javob
Asl xato — uning turi, matni va stack i. Yuqoridagi kod faqat "Bron saqlanmadi" ni ko'radi, nega saqlanmagani esa izsiz ketdi. To'g'risi: throw new Error("Bron saqlanmadi", { cause: xato });.
6. Error.isError: haqiqiy xatomi?
catch dagi qiymat haqiqiy xato ekanini tekshirish kerak bo'lsa (masalan, kimdir satr tashlagan bo'lishi mumkin), birinchi yo'l — instanceof Error. U deyarli har doim ishlaydi. Faqat bitta holatda adashadi: xato boshqa global muhitda yaratilganda.
Brauzerda har iframe ning o'z window i va o'z Error klassi bor (Global obyekt va globalThis). Bunday alohida global muhit realm ("olam") deb ataladi. Ramka ichida yaratilgan xato — boshqa olamning Error idan, shuning uchun bizning Error uchun instanceof false beradi. Node'da ham shunday olam yaratish mumkin — node:vm moduli bilan (u Node'ning maxsus vositasi; import qatorini Nega modullar darsida o'rganamiz, hozir faqat natijaga qarang):
import vm from "node:vm";
const begona = vm.runInNewContext('new TypeError("boshqa olamdan")');
console.log(begona instanceof Error); // false
console.log(Error.isError(begona)); // true
console.log(Error.isError({ name: "Error", message: "x" })); // falseError.isError(qiymat) — "bu haqiqiy xato obyektimi?" degan savolga olamdan qat'i nazar to'g'ri javob beradi. Xatoga o'xshatib yasalgan oddiy obyektni esa rad etadi.
Holati: ES2026 standartida (TC39 4-bosqich). Node 24 va Chrome 134+ da bor, Firefox 138+ da ham. Safari'da hali yo'q — Baseline ma'lumotiga ko'ra u Baseline emas. Shuning uchun brauzer kodida hozircha instanceof Error ni ishlating. Ramkalar bilan ishlaydigan kutubxonalar va Node uchun Error.isError — yangi, aniq vosita.
7. Brauzerda: bron formasi
Bron sahifasidagi tekshiruv — alohida funksiyada, qoidalar throw bilan. Forma yuborilganda xato ushlanadi va foydalanuvchiga ko'rsatiladi:
<style>
body { margin: 1rem; font: 1rem/1.5 system-ui, sans-serif; }
input, button { font: inherit; min-height: 2.75rem; }
#javob { min-height: 1.5em; font-weight: bold; }
</style>
<form id="bron" novalidate>
<label for="odam">Necha kishi?</label>
<input id="odam" type="number" value="4">
<label for="vaqt">Soat</label>
<input id="vaqt" type="time" value="19:00">
<button>Bron qilish</button>
</form>
<p id="javob" aria-live="polite"></p>
<script>
function bronniTekshir(odam, vaqt) {
if (!Number.isInteger(odam) || odam < 1) {
throw new RangeError("Odam soni kamida 1 bo'lsin.");
}
if (odam > 20) {
throw new RangeError(`Ko'pi bilan 20 kishi. Siz: ${odam}.`);
}
if (vaqt < "10:00" || vaqt > "22:00") {
throw new RangeError("Bron 10:00–22:00 da qabul qilinadi.");
}
}
const forma = document.getElementById("bron");
const javob = document.getElementById("javob");
forma.addEventListener("submit", (event) => {
event.preventDefault();
const odam = Number(forma.odam.value);
const vaqt = forma.vaqt.value;
try {
bronniTekshir(odam, vaqt);
javob.textContent = `${odam} kishilik stol, soat ${vaqt}.`;
} catch (xato) {
if (!(xato instanceof RangeError)) {
throw xato;
}
javob.textContent = xato.message;
}
});
try {
bronniTekshir(25, "19:00");
} catch (xato) {
console.log(String(xato));
}
</script>Konsolda:
RangeError: Ko'pi bilan 20 kishi. Siz: 25.Sinab ko'ring:
- «Bron qilish» — "4 kishilik stol, soat 19:00.".
- Odam sonini 25 qiling — xabar
throwdagi matnning o'zi. Soatni 23:00 qiling — vaqt qoidasi. - Maydonni bo'shating —
Number("")—0, "kamida 1" xabari.
Kodga qarang: bronniTekshir ekran haqida hech narsa bilmaydi. U faqat qoidalarni tekshiradi va buzilganini throw bilan aytadi. Xabarni qayerga yozish — chaqiruvchining ishi. Shuning uchun bu funksiyani Node'da, brauzersiz sinash mumkin. Ertaga Telegram bot ham bron qabul qilsa, u ham shu funksiyani ishlatadi — xabarni esa chatga yozadi.
catch dagi instanceof RangeError — o'tgan darsdagi "faqat o'zimiznikini hal qilamiz" qoidasi. Lekin u ham to'liq aniq emas: RangeError ni JavaScript'ning o'zi ham tashlaydi (masalan, toFixed(200)). Bizning bron xatolarimizni boshqalardan aniq ajratish uchun o'z xato klassimiz kerak — keyingi darsda.
8. Ko'p uchraydigan xatolar
8.1 Satr tashlash
throw "Stol band" — message va stack yo'q. Tuzatish: throw new Error("Stol band").
8.2 O'rashda sababni yo'qotish
catch (xato) { throw new Error("Saqlanmadi"); } — asl xato izsiz ketdi. Tuzatish: { cause: xato }.
8.3 Foydalanuvchiga stack ko'rsatish
javob.textContent = xato.stack — foydalanuvchi fayl yo'llarini va funksiya nomlarini ko'radi. Bu tushunarsiz va xavfli: hujumchi ilovaning ichki tuzilishini bilib oladi. Tuzatish: foydalanuvchiga — tayyor message yoki umumiy xabar, stack — faqat konsol va loglarga (Xato strategiyasi).
8.4 throw dan keyin yangi qator
SyntaxError: Illegal newline after throw — «throw dan keyin yangi qator yo'q» bo'limi. Tuzatish: throw new Error(...) bitta qatorda boshlansin; uzun matnni qavs ichida keyingi qatorga o'tkazing.
8.5 Odatiy natija uchun throw
find o'xshash "topilmadi" holati uchun xato tashlash — chaqiruvchini har joyda try yozishga majbur qiladi. Tuzatish: "yo'q" — odatiy javob bo'lsa, undefined yoki null qaytaring; throw — funksiya va'da qilgan ishni bajara olmaganda.
9. Mashqlar
1-mashq (oson): Narx tekshiruvi
narxniTekshir(narx) funksiyasini yozing: narx son bo'lmasa — TypeError, son bo'lsa-yu 0 yoki manfiy bo'lsa — RangeError tashlasin, aks holda narxni qaytarsin. Uch qiymat bilan sinang: 35000, "35000", -1. Har birini alohida try ichida chaqiring va String(xato) ni chiqaring.
Yechim
function narxniTekshir(narx) {
if (typeof narx !== "number") {
throw new TypeError(`Narx son bo'lsin: ${narx}`);
}
if (narx <= 0) {
throw new RangeError(`Narx musbat bo'lsin: ${narx}`);
}
return narx;
}
for (const qiymat of [35000, "35000", -1]) {
try {
console.log(narxniTekshir(qiymat));
} catch (xato) {
console.log(String(xato));
}
}Konsolda:
35000
TypeError: Narx son bo'lsin: 35000
RangeError: Narx musbat bo'lsin: -1Ikkinchi qatorda 35000 raqami ko'rinadi, lekin xato turi bu qiymat satr ekanini aytadi. Tur tanlash xabarning yarmini o'zi aytadi.
2-mashq (o'rta): Setter xato tashlasin
Getter/setter va static darsida Taom ning narx setter'i noto'g'ri qiymatni console.warn bilan bildirgan edi. O'sha darsda "real kodda setter xato tashlaydi" degandik. Setter'ni shunday o'zgartiring: musbat son bo'lmasa — RangeError. osh.narx = -100 ni try ichida sinang va narx o'zgarmaganini tekshiring.
class Taom {
#narx = 0;
constructor(nom, narx) {
this.nom = nom;
this.narx = narx;
}
get narx() {
return this.#narx;
}
set narx(qiymat) {
// shu yerni o'zgartiring
}
}Yechim
class Taom {
#narx = 0;
constructor(nom, narx) {
this.nom = nom;
this.narx = narx;
}
get narx() {
return this.#narx;
}
set narx(qiymat) {
if (typeof qiymat !== "number" || qiymat <= 0) {
throw new RangeError(`Narx musbat son bo'lsin: ${qiymat}`);
}
this.#narx = qiymat;
}
}
const osh = new Taom("Osh", 35000);
try {
osh.narx = -100;
} catch (xato) {
console.log(xato.message); // Narx musbat son bo'lsin: -100
}
console.log(osh.narx); // 35000throw this.#narx = qiymat dan oldin turibdi — shuning uchun narx o'zgarmadi. Endi konstruktor ham himoyalangan: new Taom("Osh", 0) nusxa yaratmaydi, chunki konstruktor ichidagi this.narx = narx setter'ni chaqiradi. console.warn bilan esa narxi 0 bo'lgan taom jimgina yaratilardi.
3-mashq (qiyin): Sabablar zanjiri
Uch funksiya yozing:
bronniOqi(matn)—JSON.parse; xato bo'lsa —Error("Bron matni buzilgan"),causebilan.stolniTop(matn)—bronniOqini chaqirib, bronstolini qaytaradi; xato bo'lsa —Error("Stol topilmadi"),causebilan.zanjirniChiqar(xato)— zanjirdagi har xatoniname: messageko'rinishida, chekinish bilan chiqaradi: har keyingi sabab 2 bo'sh joy ichkariroq.
stolniTop('{"stol": 4') bilan sinang.
Yechim
function bronniOqi(matn) {
try {
return JSON.parse(matn);
} catch (xato) {
throw new Error("Bron matni buzilgan", { cause: xato });
}
}
function stolniTop(matn) {
try {
return bronniOqi(matn).stol;
} catch (xato) {
throw new Error("Stol topilmadi", { cause: xato });
}
}
function zanjirniChiqar(xato) {
let joriy = xato;
let chuqurlik = 0;
while (joriy) {
const chekinish = " ".repeat(chuqurlik * 2);
console.log(`${chekinish}${joriy.name}: ${joriy.message}`);
joriy = joriy.cause;
chuqurlik++;
}
}
try {
stolniTop('{"stol": 4');
} catch (xato) {
zanjirniChiqar(xato);
}Konsolda:
Error: Stol topilmadi
Error: Bron matni buzilgan
SyntaxError: Expected ',' or '}' after property value in JSON at position 10 (line 1 column 11)Har qavat o'z tilida gapiradi: yuqorida — "stol topilmadi" (foydalanuvchi vazifasi), o'rtada — "bron matni buzilgan" (ma'lumot), pastda — JSON'ning texnik sababi. Node ham ushlanmagan xatoni xuddi shunday — [cause] bilan ichma-ich — ko'rsatadi.
4-mashq: Vazifalar qadami — jim xatolarni ochiq qilish
feature/import branch'ida davom etamiz. O'tgan darsda uch ochiq muammo qolgan edi. Bugun ikkitasini yopamiz:
{"versiya": 2, ...}— ro'yxat jimgina bo'shaydi.null— "Matn JSON emas" deb noto'g'ri xabar.
Talablar:
paketniOqihech qachon[]bilan "yolg'on gapirmasin": noto'g'ri versiya, obyekt bo'lmagan JSON vavazifalarsiz paket uchun — har biri o'z o'zbekchamessagei bilanErrortashlasin.JSON.parsexatosi o'ralsin: tushunarlimessageva aslSyntaxError—causeda.- Tinglovchida bitta
try...catch:paketniOqidanroyxatniAlmashtirgacha.catchxato.messageni#import-xatoga yozsin.
Yechim
paketniOqi — "3. Hisoblovchi funksiyalar" da (qolgan 35-himoya nomlari o'zgarmaydi):
function paketniOqi(matn) {
let xom;
try {
xom = JSON.parse(matn);
} catch (xato) {
throw new Error("Matn JSON emas. Eksportni to'liq oling.", {
cause: xato,
});
}
if (!oddiyObyektmi(xom)) {
throw new Error("Bu matn vazifalar eksporti emas.");
}
const paket = xavfsizBirlashtir({}, xom);
if (paket.versiya !== 1) {
throw new Error(`Versiya ${paket.versiya} o'qilmaydi — faqat 1.`);
}
if (!Array.isArray(paket.vazifalar)) {
throw new Error("Matnda vazifalar ro'yxati yo'q.");
}
return paket.vazifalar.map(vazifaniOl);
}Tinglovchi — let malumotlar va return endi kerak emas:
importTugma.addEventListener("click", () => {
importXatosiniTozala();
elonQil("");
try {
const malumotlar = paketniOqi(importMatn.value);
royxatniAlmashtir(malumotlar);
elonQil(`${malumotlar.length} ta vazifa import qilindi.`);
} catch (xato) {
importXatosiniKorsat(xato.message);
}
});Nimaga e'tibor bering:
oddiyObyektmi—xavfsizBirlashtirdan oldin.nullni endiObject.keysga bermaymiz.oddiyObyektmimassivni ham rad etadi: eski eksport ([...]— JSON asoslari darsidagi birinchi format) ham "eksport emas" deb aniq aytiladi.tryichidatry.paketniOqidagi ichkitryfaqatJSON.parseni o'raydi va xatoni ma'noli xatoga aylantiradi. Tashqitry— tinglovchida — barcha xatolarni foydalanuvchiga ko'rsatadi.- Xabarlar
throwda yoziladi. Tinglovchi qaysi qoida buzilganini bilmaydi va bilishi shart emas: matn tayyor keladi. Yangi qoida qo'shilsa — faqatpaketniOqio'zgaradi. - Holat oxirida o'zgaradi.
royxatniAlmashtirpaketniOqimuvaffaqiyatli tugagandan keyingina chaqiriladi.throwuni "chetlab o'tadi".
Node'da paketniOqi ni to'rt holatda sinang (35-himoya nomlari qisqartirilgan — himoya bu sinovda kerak emas):
function oddiyObyektmi(q) {
return typeof q === "object" && q !== null && !Array.isArray(q);
}
function paketniOqi(matn) {
let xom;
try {
xom = JSON.parse(matn);
} catch (xato) {
throw new Error("Matn JSON emas.", { cause: xato });
}
if (!oddiyObyektmi(xom)) {
throw new Error("Bu matn vazifalar eksporti emas.");
}
if (xom.versiya !== 1) {
throw new Error(`Versiya ${xom.versiya} o'qilmaydi — faqat 1.`);
}
if (!Array.isArray(xom.vazifalar)) {
throw new Error("Matnda vazifalar ro'yxati yo'q.");
}
return xom.vazifalar;
}
const matnlar = [
'{"versiya": 1, "vazifalar": []}',
'{"versiya": 1, "vazifalar": [}',
'{"versiya": 2, "vazifalar": []}',
"null",
];
for (const matn of matnlar) {
try {
console.log("O'qildi:", paketniOqi(matn).length);
} catch (xato) {
console.log(`${xato.message} | sabab: ${xato.cause?.name}`);
}
}Konsolda:
O'qildi: 0
Matn JSON emas. | sabab: SyntaxError
Versiya 2 o'qilmaydi — faqat 1. | sabab: undefined
Bu matn vazifalar eksporti emas. | sabab: undefinedBirinchi qator — haqiqatan bo'sh eksport: endi u xatodan aniq farq qiladi. cause faqat JSON xatosida bor — qolganlarida asl xato yo'q, chunki ularni JavaScript emas, biz topdik.
Brauzerda sinab ko'ring (Chrome 154 da tekshirilgan):
{"versiya": 2, "vazifalar": [...]}— qizil "Versiya 2 o'qilmaydi — faqat 1.", ro'yxat o'zgarmadi, fokus maydonda.null— "Bu matn vazifalar eksporti emas."- Buzuq JSON, to'g'ri eksport,
__proto__li paket — avvalgidek.
Bitta yangi muammoni o'zingiz ko'ring. DevTools Console'da vaqtincha VazifalarRoyxati.dan ni buzing — u bizning kodimizdagi bug ni taqlid qiladi:
VazifalarRoyxati.dan = () => {
throw new TypeError("sinov: dasturchi xatosi");
};Endi to'g'ri eksportni import qiling. Maydon yonida qizil "sinov: dasturchi xatosi" chiqdi, konsol esa toza! catch bug'ni ham foydalanuvchi xatosi deb ko'rsatdi — foydalanuvchiga tushunarsiz inglizcha matn, dasturchiga esa hech qanday iz. «Faqat o'zimiznikini» ajratish uchun bizga o'z xato turimiz kerak — keyingi darsda. Sahifani yangilang — buzilgan dan yo'qoladi.
Uchinchi ochiq muammo ("bajarildi": "ha") hamon turibdi — Xato strategiyasi darsida.
Commit: Vazifalar: importda jim xatolarni throw bilan bildir.
10. Real ishda
- Funksiya "shartnomasi". Kutubxona hujjatlarida har funksiya ostida "Throws" bo'limi bo'ladi: qachon qanday xato tashlaydi. Node hujjatida ham shunday (
fs.readFileSync— fayl yo'q bo'lsaENOENT). O'z funksiyalaringizni ham shunday o'ylang: nima qaytaradi, qachon tashlaydi. cause— kutubxonalarda. Node'ningfetchi, ma'lumotlar bazasi drayverlari va ko'p npm paketlari past darajadagi xatonicausebilan o'rab beradi. Xato monitoringi xizmatlari (Sentry kabi — kursda keyinroq) zanjirni butunligicha ko'rsatadi.- Tekshiruv kutubxonalari. Formadan yoki API'dan kelgan ma'lumotni sxema bo'yicha tekshiradigan kutubxonalar (Zod kabi, kursda keyinroq) aynan
bronniTekshirkabi ishlaydi: qoida buzilsa — tushunarlimessagebilan xato. - Intervyu. "Nega satr tashlamaslik kerak?", "
Error.causenima uchun?", "return nullvathrow— qachon qaysi biri?" — ko'p uchraydi.
Xulosa
throw ifoda— xato tashlash: funksiya to'xtaydi, xato birinchicatchgacha ko'tariladi. Yangi qatorga o'tkazmang.return— "mana natija",throw— "va'da qilgan ishni bajara olmadim".Errordamessage,name,stack;stackyaratilgan paytda yoziladi — xatoni tashlash joyida yarating.- Tur ma'nosi bilan: oraliq —
RangeError, tur —TypeError, boshqa qoida —Error. - Satr yoki oddiy obyekt tashlamang:
messagevastackyo'qoladi. - O'ralgan xatoga asl sababni
{ cause: xato }bilan bog'lang; zanjirniwhilebilan o'qing.Error.isError(ES2026) — olamdan qat'i nazar tekshiruv, hali Baseline emas.
Keyingi dars: O'z xato klasslaringiz — class VazifaXatosi extends Error bilan o'z xato turingizni yasaysiz va catch da o'zingiznikini begonadan aniq ajratasiz.
Manbalar
- MDN: "throw", "Error", "Error: cause", "Error.prototype.stack", "Error.isError()" — developer.mozilla.org
- TC39: Finished Proposals — github.com/tc39/proposals (Error Cause — ES2022, Error.isError — ES2026)
- web-features 3.40 (npm paketi):
error-cause— Baseline 2021-09-20, keng 2024-03-20;is-error— Baseline emas (Safari yo'q) - ESLint: "no-throw-literal" — eslint.org/docs/latest/rules
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!