Mundarija (35)
- Bu darsda
- 1. Nega bu kerak?
- 2. Loyiha talablari
- 2.1 Dastur nima qiladi
- 2.2 Qoidalar
- 3. Reja: ma'lumot qayerdan qayerga oqadi
- 4. 1-bosqich: ma'lumot modeli
- 5. 2-bosqich: noto'g'ri yozuvlarni ajratish
- 5.1 Vazifa
- 5.2 Nega nusxa muhim?
- 6. 3-bosqich: jami va toifa bo'yicha yig'indi
- 6.1 Vazifa
- 7. 4-bosqich: foiz va limit
- 7.1 Vazifa
- 8. 5-bosqich: chiroyli hisobot
- 8.1 So'mni o'qishga qulay qilish
- 8.2 Ustunlarni tekislash
- 8.3 Jadval uchun ma'lumot
- 9. 6-bosqich: hammasini yig'amiz
- 10. Debug: NaN qayerdan chiqdi?
- 11. Saqlash va GitHub'ga yuborish
- 12. Baholash ro'yxati
- 13. Ko'p uchraydigan xatolar
- 13.1 Asl yozuvni o'zgartirib qo'yish
- 13.2 Satr summani tekshirmasdan qo'shish
- 13.3 Songa padStart
- 14. Mashqlar
- 1-mashq (oson): yangi toifa
- 2-mashq (o'rta): jamg'arma foizi
- 3-mashq (qiyin): "Agar ... bo'lsa?"
- 4-mashq: Portfolio qadami — loyiha kartasi
- 15. Real ishda
- 08-qism yakuni
- Xulosa
- Manbalar
JavaScript yakuniy loyiha: konsolda oylik byudjet dasturi
Qisqacha: Bu darsda oylik daromad va xarajatlarni hisoblaydigan Node.js dasturini noldan yozasiz. Dastur noto'g'ri yozuvlarni ajratadi, har toifaga ketgan pulni va uning ulushini hisoblaydi, limitdan oshganini ogohlantiradi va hisobot chiqaradi. Hammasi 08-qism bilimlari bilan: massiv, obyekt, toza funksiya, spread,
padStartvaconsole.table.
Bu darsda
- Kichik funksiyalarga bo'lingan to'liq dasturni bosqichma-bosqich yozasiz.
- Noto'g'ri ma'lumotni (manfiy summa, matn, kasr) topib, o'tkazib yuborasiz.
- Hisob-kitobni toza funksiyalarga, ekranga chiqarishni esa bitta joyga yig'asiz.
- Dasturdagi
NaNxatosini debug bilan topasiz. - Dasturni
mashqlarreposiga commit qilib, GitHub'ga yuborasiz va 100 ballik ro'yxat bo'yicha baholaysiz.
Oldin bilishingiz kerak: Pul va aniq hisob-kitob, Pure funksiya va side effect, Obyekt bo'ylab yurish, Spread va rest operatori.
1. Nega bu kerak?
Oy boshida Azizning kartasiga maosh tushdi. Oy oxirida u hayron: "Pul qayerga ketdi?" Xarajatlar telefondagi eslatmada yozilgan: "Bozor — 1 200 000", "Taksi — 95 000". Ro'yxat bor, lekin javob yo'q. Qaysi toifaga eng ko'p ketdi? Kafe uchun belgilagan chegaradan oshdimi? Oy oxirida qancha qoladi?
Har oy kalkulyator bilan hisoblash uzoq va zerikarli. Dasturchi bunday ishni bir marta dasturga aylantiradi, keyin faqat ro'yxatni yangilaydi. Bugun shu dasturni yozamiz. Yangi mavzu yo'q — 61 darsda o'rganganlaringiz bitta foydali dasturga yig'iladi. G'isht va sement alohida — shunchaki material. Ulardan uy qurilsa — boshqa narsa.
2. Loyiha talablari
2.1 Dastur nima qiladi
node byudjet.js buyrug'idan keyin dastur:
- Xarajatlarni tekshiradi: summa son emas, butun emas yoki manfiy bo'lsa — ogohlantirib, o'tkazib yuboradi. Toifasiz yozuv — "boshqa" toifasiga.
- Daromad, xarajat va qolgan pulni hisoblaydi.
- Har toifa yig'indisini va ulushini (foizini) hisoblaydi, limitdan oshganini ogohlantiradi.
- Ustunlarga tekislangan hisobot va
console.tablejadvalini chiqaradi.
2.2 Qoidalar
- Pul — butun so'mda. Kasr son pulda xato beradi (Pul va aniq hisob-kitob). U darsda pulni tiyinda saqlagan edik. Kundalik xarajatda tiyin yo'q, shuning uchun bu loyihada birlik — so'm, kasr summa esa yozishdagi xato. Foiz — butun son, bo'lish eng oxirida.
- Bitta funksiya — bitta ish. Har bosqich alohida funksiya.
- Hisob-kitob funksiyalari toza (pure). Ular faqat qiymat qaytaradi, ekranga hech narsa yozmaydi (Pure funksiya va side effect).
- Asl ma'lumot o'zgarmaydi. Yangi obyekt kerak bo'lsa, spread bilan nusxa olinadi.
- Yon ta'sir — faqat bitta funksiyada.
console.log,console.warnvaconsole.tablefaqatdasturniIshgaTushirichida. - Faqat 08-qism bilimlari. Ma'lumot kod ichida yoziladi. Fayldan o'qishni keyingi qismlarda o'rganamiz.
Tekshirib ko'ring: Nega hisob-kitob funksiyalari ekranga o'zi yozmasligi kerak? Axir
console.logbilan darrov ko'rinardi-ku.
Javob
Ekranga yozadigan funksiyani boshqa joyda ishlatib bo'lmaydi. Toza funksiya natijani qaytaradi — uni ekranga ham, ertaga Telegram'ga ham berish mumkin. Tekshirish ham qulay: bir xil kirish — bir xil natija. Bu Pure funksiya darsidagi "oshpaz va ofitsiant" qoidasi.
3. Reja: ma'lumot qayerdan qayerga oqadi
Kod yozishdan oldin — reja. Diagrammada har to'rtburchak — bitta funksiya. Yashillari toza (faqat hisoblaydi), to'q sariqlari ekranga chiqaradi. Ma'lumot strelkalar bo'ylab yuqoridan pastga oqadi. Kichik yordamchilar (foizHisobla, somYoz) diagrammada yo'q — ular pastdagi jadvalda.
flowchart TD
M["Ma'lumot: xarajatlar"] --> T["xarajatlarniTekshir"]
T -->|xatolar| W["console.warn"]
T -->|togrilar| J["jamiHisobla"]
T -->|togrilar| Y["toifalarBoyicha"]
J --> H["hisobotTuz"]
Y --> H
Y --> O["oshganToifalar"]
Y --> D["jadvalTuz"]
H --> L["console.log"]
O --> L
D --> C["console.table"]
classDef toza fill:#e8f1ec,stroke:#1f6f4a
classDef yon fill:#fdeee6,stroke:#b4461a
class T,J,Y,H,O,D toza
class W,L,C yonIsh olti bosqichda boradi:
| # | Bosqich | Funksiyalar | Tayanch dars |
|---|---|---|---|
| 1 | Ma'lumot modeli | — | Obyekt |
| 2 | Tekshirish | xatoSababi, xarajatlarniTekshir |
Matn ↔ son |
| 3 | Yig'indilar | jamiHisobla, toifalarBoyicha |
for...of |
| 4 | Foiz va limit | foizHisobla, oshganToifalar |
Math |
| 5 | Hisobot | somYoz, hisobQatori, hisobotTuz, jadvalTuz |
padStart |
| 6 | Yig'ish | dasturniIshgaTushir |
Pure funksiya |
Har bosqichda avval o'zingiz yozib ko'ring, keyin yechim bilan solishtiring. Qiynalsangiz — yechimni o'qing va uni ko'rmasdan qayta yozing.
Kod bloklari bir-birining davomi: oldingi bloklardagi o'zgaruvchi va funksiyalarni ishlatadi. Saytdagi "Ishga tushir" tugmasi oldingi bloklarni jim bajaradi va faqat shu blok natijasini ko'rsatadi.
4. 1-bosqich: ma'lumot modeli
Har xarajat — bitta obyekt ("kartochka"): toifa, summa va izoh. Hamma kartochkalar — bitta massivda. Bu obyektlar massivi — real dasturlarda ma'lumot deyarli doim shunday keladi. byudjet.js faylini yarating va boshiga ma'lumotni yozing:
const oy = "2026-yil oktabr";
const daromadlar = [
{ manba: "Oylik maosh", summa: 6_000_000 },
{ manba: "Frilans: sayt", summa: 1_500_000 },
];
const xarajatlar = [
{ toifa: "ijara", summa: 2_500_000, izoh: "Kvartira" },
{ toifa: "ovqat", summa: 1_200_000, izoh: "Bozor" },
{ toifa: "transport", summa: 180_000, izoh: "Metro, avtobus" },
{ toifa: "ovqat", summa: 420_000, izoh: "Supermarket" },
{ toifa: "aloqa", summa: 150_000, izoh: "Internet, telefon" },
{ toifa: "kafe", summa: 260_000, izoh: "Do'stlar bilan" },
{ toifa: "transport", summa: 95_000, izoh: "Taksi" },
{ toifa: "kafe", summa: 140_000, izoh: "Tug'ilgan kun" },
{ toifa: "kiyim", summa: -350_000, izoh: "Krossovka" },
{ toifa: "kitob", summa: "85000", izoh: "JS kitobi" },
{ summa: 40_000, izoh: "Sartarosh" },
{ toifa: "ovqat", summa: 37_500.5, izoh: "Non" },
];
const limitlar = {
ijara: 2_500_000,
ovqat: 1_500_000,
transport: 300_000,
aloqa: 150_000,
kafe: 300_000,
};
console.log(xarajatlar.length); // 122_500_000— pastki chiziq faqat ko'z uchun, JavaScript uni2500000deb o'qiydi (Son yozish shakllari).- Oxirgi to'rtta yozuv ataylab buzuq. Hayotda ma'lumot doim toza kelmaydi: minus tasodifan bosiladi, summa qo'shtirnoqda yoziladi. Dastur bunda buzilmasligi kerak.
- Sartaroshda toifa yo'q —
yozuv.toifaundefinedbo'ladi. Uni "boshqa" toifasiga qo'yamiz. limitlar— obyekt, massiv emas. Limit toifa nomi bilan darrov topiladi:limitlar[toifa](Obyekt).
Maslahat: Summalarni o'z xarajatlaringizga almashtirsangiz, dastur siz uchun ishlaydi. Lekin GitHub'dagi repo ochiq bo'lishi mumkin — shaxsiy summalarni emas, namunani commit qiling.
5. 2-bosqich: noto'g'ri yozuvlarni ajratish
5.1 Vazifa
Ikki funksiya yozing:
xatoSababi(summa)— summa to'g'ri bo'lsanull, aks holda sababini matn bilan qaytaradi. Tekshiruvlar: son emasmi (typeof), butunmi (Number.isInteger), musbatmi.xarajatlarniTekshir(royxat)— yozuvlarni ikki yangi massivga (togrilar,xatolar) ajratib, bitta obyektda qaytaradi. Toifasiz yozuvga"boshqa"qo'yadi.
Ishora: ?? — chap tomoni undefined bo'lsa o'ng tomonni oladi (?? va ?.). Sikldagi navbatdagi yozuvni tashlab ketish — continue (break va continue).
Yechim
function xatoSababi(summa) {
if (typeof summa !== "number") {
return "summa son emas";
}
if (!Number.isInteger(summa)) {
return "summa butun son emas";
}
if (summa <= 0) {
return "summa musbat emas";
}
return null;
}
function xarajatlarniTekshir(royxat) {
const togrilar = [];
const xatolar = [];
for (const yozuv of royxat) {
const sabab = xatoSababi(yozuv.summa);
if (sabab !== null) {
xatolar.push({ ...yozuv, sabab });
continue;
}
togrilar.push({ ...yozuv, toifa: yozuv.toifa ?? "boshqa" });
}
return { togrilar, xatolar };
}
console.log(xatoSababi(150_000)); // null
console.log(xatoSababi("85000")); // summa son emas
console.log(xatoSababi(37_500.5)); // summa butun son emas
console.log(xatoSababi(-350_000)); // summa musbat emasQatorma-qator:
typeof summa !== "number"birinchi turadi."85000"— satr. Uni songa aylantirmaymiz: ma'lumot noto'g'ri yozilgan, egasi tuzatsin (typeof).Number.isIntegerkasrni ushlaydi.NaNvaInfinityuchun hamfalseberadi (Matn ↔ son).summa <= 0— manfiy va nol summa.- Har tekshiruv — erta qaytish: sabab topilsa, qolganini tekshirish shart emas (return va erta qaytish).
{ ...yozuv, sabab }— yozuv nusxasi va yangisababxususiyati (sabab: sababning qisqasi — Shorthand).{ ...yozuv, toifa: yozuv.toifa ?? "boshqa" }— nusxa,toifaustidan yoziladi: spread'dan keyingi kalit ustun (Spread va rest).
Funksiya natija obyekt qaytaradi. Undan ikki massivni nuqta bilan olamiz:
const tekshiruv = xarajatlarniTekshir(xarajatlar);
console.log(tekshiruv.togrilar.length); // 9
console.log(tekshiruv.xatolar.length); // 3
console.log(tekshiruv.togrilar[8].toifa); // boshqa
console.log(xarajatlar[10].toifa); // undefined12 ta yozuvdan 9 tasi to'g'ri, 3 tasi buzuq. Oxirgi qatorga qarang: asl massivdagi sartarosh yozuvida toifa hali ham undefined. Biz aslini emas, nusxasini o'zgartirdik.
5.2 Nega nusxa muhim?
Spread'siz ham bo'lardi: yozuv.toifa = "boshqa" va togrilar.push(yozuv). Lekin yozuv — asl obyektga havola, nusxa emas (Havola semantikasi). Bunday funksiya asl ma'lumotni jimgina o'zgartiradi — bu yon ta'sir. { ...yozuv } — bunga qarshi eng arzon himoya. ko'rinishini «Ko'p uchraydigan xatolar» bo'limida ishga tushirasiz.
Diqqat: Spread — sayoz nusxa, faqat birinchi qavat (Sayoz va chuqur nusxalash). Yozuvlarimizda ichma-ich obyekt yo'q, shuning uchun spread yetarli. Ichida obyekt bo'lsa,
structuredClonekerak bo'lardi.
Tekshirib ko'ring:
xatoSababi(NaN)nima qaytaradi va nega?
Javob
"summa butun son emas". typeof NaN — "number" (Number turi), shuning uchun birinchi tekshiruvdan o'tadi. Number.isInteger(NaN) esa false — ikkinchi tekshiruv ushlaydi.
6. 3-bosqich: jami va toifa bo'yicha yig'indi
6.1 Vazifa
jamiHisobla(royxat)—summali yozuvlar massivining yig'indisi. Daromadlar uchun ham, xarajatlar uchun ham ishlasin.toifalarBoyicha(royxat)— obyekt qaytaradi: kalit — toifa, qiymat — shu toifa yig'indisi.
Ishora: bu yerda obyekt hisoblagich bo'ladi. Toifa birinchi uchraganda u obyektda hali yo'q.
Yechim
function jamiHisobla(royxat) {
let jami = 0;
for (const { summa } of royxat) {
jami += summa;
}
return jami;
}
function toifalarBoyicha(royxat) {
const yigindilar = {};
for (const { toifa, summa } of royxat) {
yigindilar[toifa] = (yigindilar[toifa] ?? 0) + summa;
}
return yigindilar;
}
console.log(jamiHisobla(daromadlar)); // 7500000
console.log(jamiHisobla(tekshiruv.togrilar)); // 4985000for (const { summa } of royxat)— sikl o'zgaruvchisida destructuring: har yozuvdan faqatsummaolinadi (Parametrda destructuring). Shuning uchun funksiya daromad uchun ham ishlaydi.yigindilar[toifa]— kvadrat qavs, chunki kalit nomi o'zgaruvchida (Obyekt).yigindilar.toifaesa "toifa" degan kalit yaratardi.(yigindilar[toifa] ?? 0) + summa— eng muhim qator. Toifa birinchi uchraganda u yerdaundefined,?? 0uni 0 ga almashtiradi.
Hisoblagich qanday to'lishini kichik ro'yxatda ko'ring. Keyingi tugmasini bosib, yigindilar ga qarang: "ovqat" ikkinchi marta kelganda yangi kalit ochilmaydi, eski qiymatga qo'shiladi.
Endi haqiqiy ma'lumot bilan:
const yigindilar = toifalarBoyicha(tekshiruv.togrilar);
console.log(Object.keys(yigindilar).length); // 6
console.log(yigindilar.ovqat); // 1620000
console.log(yigindilar.boshqa); // 40000Olti toifa. "Ovqat" — ikkita to'g'ri yozuvdan: 1 200 000 + 420 000. Kasrli non tekshiruvdan o'tmagan edi.
Bo'sh joyni to'ldiring. undefined ?? 0 ning natijasi — [:0]. Agar ?? 0 ni olib tashlasak, undefined + 260000 natijasi — [:NaN].
7. 4-bosqich: foiz va limit
7.1 Vazifa
foizHisobla(qism, jami)—qismjamining necha foizi — butun son.jami0 bo'lsa — 0.oshganToifalar(yigindilar, limitlar)— limitdan oshgan toifalar:{ toifa, sarf, limit, ortiqcha }massivi. Limitsiz toifa tekshirilmaydi.
Ishora: obyektni kalit-qiymat juftliklari bilan aylanish — Object.entries (Obyekt bo'ylab yurish).
Yechim
function foizHisobla(qism, jami) {
if (jami === 0) {
return 0;
}
return Math.round((qism * 100) / jami);
}
function oshganToifalar(yigindilar, limitlar) {
const oshganlar = [];
for (const [toifa, sarf] of Object.entries(yigindilar)) {
const limit = limitlar[toifa];
if (limit === undefined) {
continue;
}
if (sarf > limit) {
oshganlar.push({ toifa, sarf, limit, ortiqcha: sarf - limit });
}
}
return oshganlar;
}
console.log(foizHisobla(2_500_000, 4_985_000)); // 50
console.log(foizHisobla(150_000, 0)); // 0(qism * 100) / jami— avval butun songa ko'paytirish, bo'lish oxirida va bitta (Pul darsidagi qoida).Math.round— eng yaqin butun songa: 50,15% → 50% (Math).if (jami === 0) return 0— nolga bo'lish xato bermaydi, lekinNaNyokiInfinityqaytaradi. Oy boshida xarajat yo'q bo'lsa, hisobotdaNaN%chiqmasin.const [toifa, sarf]—Object.entrieshar juftlikni["ovqat", 1620000]qilib beradi, massiv destructuring uni ikkiga ajratadi (Massiv destructuring).sarf > limit,>=emas: ijara aynan limitga teng — bu oshish emas (Taqqoslash operatorlari).
const oshganlar = oshganToifalar(yigindilar, limitlar);
const [birinchi, ikkinchi] = oshganlar;
console.log(oshganlar.length); // 2
console.log(birinchi.toifa, birinchi.ortiqcha); // ovqat 120000
console.log(ikkinchi.toifa, ikkinchi.ortiqcha); // kafe 100000Ovqat 120 000, kafe 100 000 so'mga oshgan. Transport va ijara — joyida.
Tekshirib ko'ring: Hamma toifalarning foizlarini qo'shsak, doim aniq 100 chiqadimi?
Javob
Yo'q. Har foiz alohida yaxlitlanadi: uchta teng toifa — har biri 33,33% → 33%, yig'indisi 99%. Ba'zan 101% chiqadi. Bu Pul darsidagi "qismlarni alohida yaxlitlash" tuzog'i. Bizda yig'indi aniq 100 chiqdi — omad. Foiz taxminiy ko'rsatkich, aniq raqam summa ustunida.
8. 5-bosqich: chiroyli hisobot
8.1 So'mni o'qishga qulay qilish
2500000 ni bir qarashda o'qish qiyin: 250 ming? 2,5 million? Hisobotda 2 500 000 kerak. somYoz(son) raqamlarni o'ngdan uchtadan guruhlaydi. G'oya: raqamlarni chapdan o'ngga yuramiz. Har raqamdan oldin tekshiramiz: o'ngida qolgan raqamlar soni 3 ga bo'linadimi? Bo'linsa — bo'sh joy.
function somYoz(son) {
const raqamlar = String(Math.abs(son));
let natija = "";
for (let i = 0; i < raqamlar.length; i++) {
const qolgani = raqamlar.length - i;
if (i > 0 && qolgani % 3 === 0) {
natija += " ";
}
natija += raqamlar[i];
}
return son < 0 ? `-${natija}` : natija;
}
console.log(somYoz(2_515_000)); // 2 515 000
console.log(somYoz(95_000)); // 95 000
console.log(somYoz(500)); // 500
console.log(somYoz(-120_000)); // -120 000qolgani — joriy raqamning o'zi va undan o'ngdagilar soni. Masalan, "2515000" da 7 ta raqam. Ikkinchi raqam "5" da (i = 1) qolgani = 6, ya'ni "515000". 6 % 3 = 0 — demak "5" dan oldin bo'sh joy. Beshinchi raqamda (i = 4) qolgani = 3 — yana bo'sh joy. Nega i > 0 sharti kerak? "500000" da birinchi raqamning o'zida ham qolgani = 6. Shartsiz satr boshida ortiqcha bo'sh joy paydo bo'lardi. Yordamchilar: String() sonni satrga aylantiradi (Turlarni aniq o'zgartirish). Math.abs minusni vaqtincha olib tashlaydi. % — bo'lishdagi qoldiq (Arifmetik operatorlar).
Maslahat: Real loyihada buni Pul darsidagi
Intl.NumberFormatqiladi. Bu yerda mashq uchun o'zimiz yozdik.
8.2 Ustunlarni tekislash
Chekdagi kabi: nom chapda, summa o'ngda. Kesish, bo'lish va to'ldirish darsidagi ikki metod:
"ovqat".padEnd(12)— oxiriga bo'sh joy qo'shib, uzunlikni 12 ga yetkazadi: nom chapga tekislanadi."1 620 000".padStart(16)— boshiga bo'sh joy qo'shadi: son o'ngga tekislanadi.
padStart faqat satrda bor — shuning uchun avval somYoz, keyin padStart. Template literal natijasi ham satr, shuning uchun unga ham padStart qo'yish mumkin. Kenglik: 12 + 24 = 36 — chiziq uzunligi. Jadval qatorida ham 12 + 16 + 8 = 36. hisobQatori bitta "nom ... summa so'm" qatorini qaytaradi. hisobotTuz butun hisobotni qatorlar massivi qilib qaytaradi — ekranga yozmaydi.
function hisobQatori(nom, summa) {
return nom.padEnd(12) + `${somYoz(summa)} so'm`.padStart(24);
}
function hisobotTuz({ oy, daromad, xarajat, yigindilar }) {
const chiziq = "=".repeat(36);
const qatorlar = [chiziq, ` OYLIK BYUDJET — ${oy}`, chiziq];
qatorlar.push(hisobQatori("Daromad:", daromad));
qatorlar.push(hisobQatori("Xarajat:", xarajat));
qatorlar.push(hisobQatori("Qoldi:", daromad - xarajat));
qatorlar.push("-".repeat(36));
qatorlar.push(
"Toifa".padEnd(12) + "Summa".padStart(16) + "Ulush".padStart(8),
);
for (const [toifa, summa] of Object.entries(yigindilar)) {
const summaMatn = somYoz(summa).padStart(16);
const ulush = `${foizHisobla(summa, xarajat)}%`.padStart(8);
qatorlar.push(toifa.padEnd(12) + summaMatn + ulush);
}
return qatorlar;
}
console.log(hisobQatori("Qoldi:", 2_515_000));Bu blokni ishga tushirsangiz, bitta qator chiqadi — nom chapda, summa o'ngda, jami 36 belgi:
Qoldi: 2 515 000 so'mhisobotTuz to'rtta alohida parametr o'rniga bitta options obyekti oladi: chaqirishda tartibni adashtirib bo'lmaydi, har qiymat nomi bilan beriladi (Parametrda destructuring va options obyekti).
8.3 Jadval uchun ma'lumot
console.table obyektlar massivini jadval qilib chizadi: obyekt — qator, kalit — ustun (console API). Shunday massiv tayyorlaymiz:
function jadvalTuz(yigindilar, limitlar) {
const jadval = [];
for (const [toifa, sarf] of Object.entries(yigindilar)) {
const limit = limitlar[toifa] ?? null;
let holat = "limitsiz";
if (limit !== null) {
holat = sarf > limit ? "OSHDI" : "joyida";
}
jadval.push({ toifa, sarf, limit, holat });
}
return jadval;
}
const jadval = jadvalTuz(yigindilar, limitlar);
console.log(jadval[1].toifa, jadval[1].holat); // ovqat OSHDIjadval[1] — massivning ikkinchi elementi, "ovqat" qatori. Limiti yo'q toifada limitlar[toifa] — undefined. ?? null uni null ga almashtiradi: "ataylab yo'q" ma'nosi aniqroq (undefined va null). holat — ternary bilan (Ternary).
Bo'sh joyni to'ldiring. "kafe".padEnd(12) qaytargan satr uzunligi — belgi.
9. 6-bosqich: hammasini yig'amiz
"Oshpazlar" tayyor. Endi "ofitsiant" — natijani foydalanuvchiga yetkazadigan yagona funksiya. Hamma yon ta'sir shu yerda:
function dasturniIshgaTushir() {
const { togrilar, xatolar } = xarajatlarniTekshir(xarajatlar);
for (const x of xatolar) {
console.warn(`⚠️ O'tkazildi: "${x.izoh}" — ${x.sabab}`);
}
const daromad = jamiHisobla(daromadlar);
const xarajat = jamiHisobla(togrilar);
const yigindilar = toifalarBoyicha(togrilar);
const hisobot = hisobotTuz({ oy, daromad, xarajat, yigindilar });
for (const q of hisobot) {
console.log(q);
}
for (const o of oshganToifalar(yigindilar, limitlar)) {
console.log(
`🔴 ${o.toifa}: limit ${somYoz(o.limit)}, ` +
`${somYoz(o.ortiqcha)} so'm oshdi`,
);
}
console.table(jadvalTuz(yigindilar, limitlar));
}
dasturniIshgaTushir();Terminalda node byudjet.js ni ishga tushiring. Mana Aziz kompyuterida chiqqan to'liq natija:
⚠️ O'tkazildi: "Krossovka" — summa musbat emas
⚠️ O'tkazildi: "JS kitobi" — summa son emas
⚠️ O'tkazildi: "Non" — summa butun son emas
====================================
OYLIK BYUDJET — 2026-yil oktabr
====================================
Daromad: 7 500 000 so'm
Xarajat: 4 985 000 so'm
Qoldi: 2 515 000 so'm
------------------------------------
Toifa Summa Ulush
ijara 2 500 000 50%
ovqat 1 620 000 32%
transport 275 000 6%
aloqa 150 000 3%
kafe 400 000 8%
boshqa 40 000 1%
🔴 ovqat: limit 1 500 000, 120 000 so'm oshdi
🔴 kafe: limit 300 000, 100 000 so'm oshdi
┌─────────┬─────────────┬─────────┬─────────┬────────────┐
│ (index) │ toifa │ sarf │ limit │ holat │
├─────────┼─────────────┼─────────┼─────────┼────────────┤
│ 0 │ 'ijara' │ 2500000 │ 2500000 │ 'joyida' │
│ 1 │ 'ovqat' │ 1620000 │ 1500000 │ 'OSHDI' │
│ 2 │ 'transport' │ 275000 │ 300000 │ 'joyida' │
│ 3 │ 'aloqa' │ 150000 │ 150000 │ 'joyida' │
│ 4 │ 'kafe' │ 400000 │ 300000 │ 'OSHDI' │
│ 5 │ 'boshqa' │ 40000 │ null │ 'limitsiz' │
└─────────┴─────────────┴─────────┴─────────┴────────────┘Natijani o'qing:
- Uchta buzuq yozuv dasturni to'xtatmadi — ogohlantirish bilan chetga olindi.
console.warnNode'da xato oqimiga (stderr) yozadi (console API); terminalda u oddiy qatorlar orasida ko'rinadi. - Aziz oy oxirida 2 515 000 so'm bilan qoladi. Pulning yarmi ijaraga ketyapti, ovqat va kafe limitdan oshgan.
- Jadvalda summalar formatlanmagan:
console.tableqiymatni o'zgartirmay ko'rsatadi. Matnli hisobot — odam uchun, jadval — tez tekshirish uchun.
dasturniIshgaTushir deyarli gap kabi o'qiladi: tekshir, hisobla, tuz, chiqar. Xato chiqsa, qaysi funksiyaga qarash kerakligi darrov ko'rinadi.
To'liq fayl: byudjet.js (nusxa olish uchun)
Bosqichlardan yig'ilgan fayl. Sinov qatorlari (console.log(xatoSababi(...)) va boshqalar) olib tashlangan.
// byudjet.js — oylik byudjet hisoboti (08-qism yakuniy loyihasi)
// 1. Ma'lumot
const oy = "2026-yil oktabr";
const daromadlar = [
{ manba: "Oylik maosh", summa: 6_000_000 },
{ manba: "Frilans: sayt", summa: 1_500_000 },
];
const xarajatlar = [
{ toifa: "ijara", summa: 2_500_000, izoh: "Kvartira" },
{ toifa: "ovqat", summa: 1_200_000, izoh: "Bozor" },
{ toifa: "transport", summa: 180_000, izoh: "Metro, avtobus" },
{ toifa: "ovqat", summa: 420_000, izoh: "Supermarket" },
{ toifa: "aloqa", summa: 150_000, izoh: "Internet, telefon" },
{ toifa: "kafe", summa: 260_000, izoh: "Do'stlar bilan" },
{ toifa: "transport", summa: 95_000, izoh: "Taksi" },
{ toifa: "kafe", summa: 140_000, izoh: "Tug'ilgan kun" },
{ toifa: "kiyim", summa: -350_000, izoh: "Krossovka" },
{ toifa: "kitob", summa: "85000", izoh: "JS kitobi" },
{ summa: 40_000, izoh: "Sartarosh" },
{ toifa: "ovqat", summa: 37_500.5, izoh: "Non" },
];
const limitlar = {
ijara: 2_500_000,
ovqat: 1_500_000,
transport: 300_000,
aloqa: 150_000,
kafe: 300_000,
};
// 2. Tekshirish
function xatoSababi(summa) {
if (typeof summa !== "number") {
return "summa son emas";
}
if (!Number.isInteger(summa)) {
return "summa butun son emas";
}
if (summa <= 0) {
return "summa musbat emas";
}
return null;
}
function xarajatlarniTekshir(royxat) {
const togrilar = [];
const xatolar = [];
for (const yozuv of royxat) {
const sabab = xatoSababi(yozuv.summa);
if (sabab !== null) {
xatolar.push({ ...yozuv, sabab });
continue;
}
togrilar.push({ ...yozuv, toifa: yozuv.toifa ?? "boshqa" });
}
return { togrilar, xatolar };
}
// 3. Hisob-kitob
function jamiHisobla(royxat) {
let jami = 0;
for (const { summa } of royxat) {
jami += summa;
}
return jami;
}
function toifalarBoyicha(royxat) {
const yigindilar = {};
for (const { toifa, summa } of royxat) {
yigindilar[toifa] = (yigindilar[toifa] ?? 0) + summa;
}
return yigindilar;
}
function foizHisobla(qism, jami) {
if (jami === 0) {
return 0;
}
return Math.round((qism * 100) / jami);
}
function oshganToifalar(yigindilar, limitlar) {
const oshganlar = [];
for (const [toifa, sarf] of Object.entries(yigindilar)) {
const limit = limitlar[toifa];
if (limit === undefined) {
continue;
}
if (sarf > limit) {
oshganlar.push({ toifa, sarf, limit, ortiqcha: sarf - limit });
}
}
return oshganlar;
}
// 4. Ko'rinish
function somYoz(son) {
const raqamlar = String(Math.abs(son));
let natija = "";
for (let i = 0; i < raqamlar.length; i++) {
const qolgani = raqamlar.length - i;
if (i > 0 && qolgani % 3 === 0) {
natija += " ";
}
natija += raqamlar[i];
}
return son < 0 ? `-${natija}` : natija;
}
function hisobQatori(nom, summa) {
return nom.padEnd(12) + `${somYoz(summa)} so'm`.padStart(24);
}
function hisobotTuz({ oy, daromad, xarajat, yigindilar }) {
const chiziq = "=".repeat(36);
const qatorlar = [chiziq, ` OYLIK BYUDJET — ${oy}`, chiziq];
qatorlar.push(hisobQatori("Daromad:", daromad));
qatorlar.push(hisobQatori("Xarajat:", xarajat));
qatorlar.push(hisobQatori("Qoldi:", daromad - xarajat));
qatorlar.push("-".repeat(36));
qatorlar.push(
"Toifa".padEnd(12) + "Summa".padStart(16) + "Ulush".padStart(8),
);
for (const [toifa, summa] of Object.entries(yigindilar)) {
const summaMatn = somYoz(summa).padStart(16);
const ulush = `${foizHisobla(summa, xarajat)}%`.padStart(8);
qatorlar.push(toifa.padEnd(12) + summaMatn + ulush);
}
return qatorlar;
}
function jadvalTuz(yigindilar, limitlar) {
const jadval = [];
for (const [toifa, sarf] of Object.entries(yigindilar)) {
const limit = limitlar[toifa] ?? null;
let holat = "limitsiz";
if (limit !== null) {
holat = sarf > limit ? "OSHDI" : "joyida";
}
jadval.push({ toifa, sarf, limit, holat });
}
return jadval;
}
// 5. Ishga tushirish: yon ta'sirlar shu yerda
function dasturniIshgaTushir() {
const { togrilar, xatolar } = xarajatlarniTekshir(xarajatlar);
for (const x of xatolar) {
console.warn(`⚠️ O'tkazildi: "${x.izoh}" — ${x.sabab}`);
}
const daromad = jamiHisobla(daromadlar);
const xarajat = jamiHisobla(togrilar);
const yigindilar = toifalarBoyicha(togrilar);
const hisobot = hisobotTuz({ oy, daromad, xarajat, yigindilar });
for (const q of hisobot) {
console.log(q);
}
for (const o of oshganToifalar(yigindilar, limitlar)) {
console.log(
`🔴 ${o.toifa}: limit ${somYoz(o.limit)}, ` +
`${somYoz(o.ortiqcha)} so'm oshdi`,
);
}
console.table(jadvalTuz(yigindilar, limitlar));
}
dasturniIshgaTushir();Konsolda:
⚠️ O'tkazildi: "Krossovka" — summa musbat emas
⚠️ O'tkazildi: "JS kitobi" — summa son emas
⚠️ O'tkazildi: "Non" — summa butun son emas
====================================
OYLIK BYUDJET — 2026-yil oktabr
====================================
Daromad: 7 500 000 so'm
Xarajat: 4 985 000 so'm
Qoldi: 2 515 000 so'm
------------------------------------
Toifa Summa Ulush
ijara 2 500 000 50%
ovqat 1 620 000 32%
transport 275 000 6%
aloqa 150 000 3%
kafe 400 000 8%
boshqa 40 000 1%
🔴 ovqat: limit 1 500 000, 120 000 so'm oshdi
🔴 kafe: limit 300 000, 100 000 so'm oshdi
┌─────────┬─────────────┬─────────┬─────────┬────────────┐
│ (index) │ toifa │ sarf │ limit │ holat │
├─────────┼─────────────┼─────────┼─────────┼────────────┤
│ 0 │ 'ijara' │ 2500000 │ 2500000 │ 'joyida' │
│ 1 │ 'ovqat' │ 1620000 │ 1500000 │ 'OSHDI' │
│ 2 │ 'transport' │ 275000 │ 300000 │ 'joyida' │
│ 3 │ 'aloqa' │ 150000 │ 150000 │ 'joyida' │
│ 4 │ 'kafe' │ 400000 │ 300000 │ 'OSHDI' │
│ 5 │ 'boshqa' │ 40000 │ null │ 'limitsiz' │
└─────────┴─────────────┴─────────┴─────────┴────────────┘10. Debug: NaN qayerdan chiqdi?
Loyiha birinchi urinishda kamdan-kam ishlaydi — bu normal. Aziz toifalarBoyicha ni birinchi marta shunday yozgan edi:
function toifalarBoyicha(royxat) {
const yigindilar = {};
for (const { toifa, summa } of royxat) {
yigindilar[toifa] += summa;
}
return yigindilar;
}
const sinov = [
{ toifa: "kafe", summa: 260_000 },
{ toifa: "kafe", summa: 140_000 },
];
console.log(toifalarBoyicha(sinov)); // { kafe: NaN }Kod xato bermadi, lekin natija noto'g'ri — eng yoqimsiz xato turi. Tartib bilan qidiramiz.
1-qadam: xatoni kichik misolda qayta hosil qiling. 12 ta yozuv emas — ikkita (sinov). Toza funksiyani butun dasturdan ajratib sinash mumkin.
2-qadam: ichini ko'ring. Eng tez yo'l — sikl ichiga vaqtincha console.log:
function toifalarBoyicha(royxat) {
const yigindilar = {};
for (const { toifa, summa } of royxat) {
console.log(toifa, yigindilar[toifa], summa); // vaqtincha
yigindilar[toifa] += summa;
}
return yigindilar;
}
toifalarBoyicha([
{ toifa: "kafe", summa: 260_000 },
{ toifa: "kafe", summa: 140_000 },
]);Konsolda:
kafe undefined 260000
kafe NaN 140000Topildi: birinchi aylanishda yigindilar.kafe — undefined, undefined + 260000 esa NaN (Yashirin coercion). NaN ga nima qo'shsangiz ham — NaN.
3-qadam: debugger bilan. Katta dasturda console.log yozib o'tirish charchatadi. DevTools bilan debug qilish darsidagi ikki yo'l:
- VS Code:
Ctrl+Shift+P→ JavaScript Debug Terminal.yigindilar[toifa] += summa;qatori raqamining chap tomonini bosing — qizil nuqta (breakpoint). Terminaldanode byudjet.js— dastur shu qatorda to'xtaydi. - Chrome: qatordan oldin
debugger;yozing vanode --inspect-brk byudjet.jsni ishga tushiring. Chrome'dachrome://inspect→ Open dedicated DevTools for Node, keyinF8— dasturdebuggerda to'xtaydi.
To'xtagach, Watch paneliga yigindilar[toifa] ni qo'shing — undefined. F10 bilan bir qadam yuring — kafe: NaN paydo bo'ladi. Gumon tasdiqlandi.
4-qadam: tuzating va qayta tekshiring. 3-bosqichdagi (yigindilar[toifa] ?? 0) + summa qatori bilan sinov endi { kafe: 400000 } beradi. Vaqtincha console.log va debugger qatorlarini o'chiring — unutilgan debugger dasturni kutilmaganda to'xtatadi.
Tekshirib ko'ring: Nega xatoni butun dasturda emas, ikki yozuvli
sinovmassivida qidirdik?
Javob
Kichik misolda hamma qiymat ko'rinadi: ikki aylanish, ikki qator. 12 ta yozuvda kerakli qator yo'qolib ketadi.
11. Saqlash va GitHub'ga yuborish
Endi dasturni Git qismida ochilgan mashqlar reposiga qo'shamiz: 08-qism ishlari — 08/ papkasida, loyiha — 08/byudjet/ da.
Git Bash'da:
cd ~/kurs/mashqlar
mkdir -p 08/byudjetbyudjet.js ni 08/byudjet/ ichiga saqlang va commitdan oldin ishlashini tekshiring:
node 08/byudjet/byudjet.js
git status -sNatija — yuqoridagi hisobot, keyin:
?? 08/?? — Git bu papkani hali kuzatmaydi (Birinchi repo). Commit xabari — mashqlar kelishuvi bo'yicha: avval soha (papka), keyin buyruq maylidagi fe'l (Yaxshi commit):
git add 08/byudjet
git commit -m "08/byudjet: oylik byudjet dasturini qo'sh"
git pushCommit chiqishi:
[main ac5ffe3] 08/byudjet: oylik byudjet dasturini qo'sh
1 file changed, 174 insertions(+)
create mode 100644 08/byudjet/byudjet.jsSizda SHA va qatorlar soni boshqacha bo'ladi — bu normal. git push dan keyin GitHub'da login/mashqlar ni oching: 08/byudjet/byudjet.js ko'rinishi kerak (Remote, push va pull).
Diqqat: Ma'lumotni o'zingiznikiga almashtirgan bo'lsangiz, commitdan oldin
git diff --stagedbilan qarang. Ochiq repoga tushgan narsani tarixdan o'chirish qiyin.
12. Baholash ro'yxati
O'zingiz baholang, yaxshisi — kursdoshingiz: begona ko'z ko'proq narsani ko'radi.
Majburiy shartlar. Bittasi bajarilmasa, loyiha qabul qilinmaydi:
node byudjet.jsxatosiz ishlaydi va hisobot chiqaradi.- Pul faqat butun so'mda hisoblanadi, kasr son yo'q.
- Dastur ishlagandan keyin asl
xarajatlaro'zgarmagan:dasturniIshgaTushir();dan keyin vaqtinchaconsole.log(xarajatlar[10].toifa);yozing —undefinedchiqishi kerak. - Fayl
mashqlarreposida,08/byudjet/papkasida, GitHub'da ko'rinadi.
Ballar (jami 100, o'tish — 80):
| Bo'lim | Nima tekshiriladi | Ball |
|---|---|---|
| Ma'lumot | Obyektlar massivi, limitlar obyekti, _ ajratgich |
10 |
| Tekshirish | Son emas, kasr, manfiy — uchalasi ushlanadi, sababi aytiladi | 15 |
| Yig'indilar | Bitta jamiHisobla ikkala ro'yxatga, toifa hisoblagichi ?? bilan |
15 |
| Foiz va limit | Butun foiz, nolga bo'lish himoyasi, > to'g'ri tanlangan |
10 |
| Hisobot | padStart/padEnd bilan tekis ustunlar, so'm guruhlangan |
15 |
| Jadval | console.table limitsiz toifani ham to'g'ri ko'rsatadi |
5 |
| Toza kod | Hisob funksiyalari toza, spread bilan nusxa, yon ta'sir bitta joyda | 15 |
| Nomlar | Har funksiya nomi bitta ishni aytadi, fe'l yoki natija nomi | 5 |
| Git | To'g'ri papka, kelishuvdagi commit xabari, push qilingan | 10 |
Har bo'limda: hammasi bajarilgan — to'liq ball, bitta kamchilik — yarmi, ko'p kamchilik — 0.
- 90–100 — a'lo: loyihani portfolio'ga qo'shing («Mashqlar» oxiri).
- 80–89 — yaxshi: kamchiliklarni tuzating.
- 80 dan kam — ball yo'qolgan bo'limning tayanch darsiga qayting. Takrorlash bilimni mustahkamlaydi.
13. Ko'p uchraydigan xatolar
13.1 Asl yozuvni o'zgartirib qo'yish
const xarajatlar = [{ summa: 40_000, izoh: "Sartarosh" }];
function toifaniTuzat(royxat) {
const natija = [];
for (const yozuv of royxat) {
yozuv.toifa = yozuv.toifa ?? "boshqa"; // ❌ aslini o'zgartiradi
natija.push(yozuv);
}
return natija;
}
toifaniTuzat(xarajatlar);
console.log(xarajatlar[0].toifa); // boshqaMassiv yangi, lekin ichida asl obyektlar — va ular o'zgardi. Endi asl ma'lumotda "boshqa" turibdi, go'yo Aziz uni o'zi kiritgandek. Tuzatish: natija.push({ ...yozuv, toifa: yozuv.toifa ?? "boshqa" }) — har yozuvning nusxasi.
13.2 Satr summani tekshirmasdan qo'shish
let jami = 0;
for (const summa of [2_500_000, "85000", 150_000]) {
jami += summa;
}
console.log(jami); // 250000085000150000Xato yo'q, lekin 18 xonali son! 2500000 + "85000" — qo'shish emas, satrlarni yopishtirish. Keyin 150000 ham yopishadi (Yashirin coercion). Shuning uchun tekshirish hisobdan oldin turadi.
13.3 Songa padStart
const summa = 2_500_000;
console.log(summa.padStart(12));Konsolda:
TypeError: summa.padStart is not a functionTarjimasi: "summa.padStart — funksiya emas". Sonda padStart yo'q, u faqat satrda bor. Tuzatish: String(summa).padStart(12) yoki bizdagidek somYoz(summa).padStart(12).
14. Mashqlar
1-mashq (oson): yangi toifa
Aziz sport zaliga yozildi. xarajatlar ga { toifa: "sport", summa: 120_000, izoh: "Zal" } ni, limitlar ga sport: 100_000 ni qo'shing. Ishga tushirishdan oldin ayting: hisobotda nima o'zgaradi? Keyin tekshiring.
Ishora: massivga yozuv — vergul bilan yangi qator, obyektga kalit — sport: 100_000, (Obyekt). O'ylab ko'ring: jami xarajat o'zgarsa, boshqa toifalarning foizlariga nima bo'ladi?
Yechim
Kod o'zgarmaydi — faqat ma'lumot. Hisobotning o'zgargan qismi:
Xarajat: 5 105 000 so'm
Qoldi: 2 395 000 so'm
------------------------------------
Toifa Summa Ulush
ijara 2 500 000 49%
ovqat 1 620 000 32%
transport 275 000 5%
aloqa 150 000 3%
kafe 400 000 8%
boshqa 40 000 1%
sport 120 000 2%
🔴 ovqat: limit 1 500 000, 120 000 so'm oshdi
🔴 kafe: limit 300 000, 100 000 so'm oshdi
🔴 sport: limit 100 000, 20 000 so'm oshdiJami o'zgargani uchun boshqa foizlar ham o'zgardi: ijara 50% → 49%, transport 6% → 5%. Yangi toifa oxirida chiqdi: Object.entries kalitlarni qo'shilgan tartibda beradi (Obyekt bo'ylab yurish). Kod o'zgarmasdan yangi toifa bilan ishladi — yaxshi tuzilgan dastur belgisi.
2-mashq (o'rta): jamg'arma foizi
jamgarmaFoizi(daromad, xarajat) funksiyasini yozing: daromadning necha foizi qolganini butun son bilan qaytarsin. Keyin jamgarmaXabari(foiz) — foiz 20 dan kam bo'lsa "⚠️ Jamg'arma 15% — 20% dan kam", aks holda "✅ Jamg'arma 34%" qaytarsin.
Ishora: tayyor foizHisobla ni qayta ishlating — qolgan pul daromad - xarajat. Matn — template literal (Template literals).
Yechim
function foizHisobla(qism, jami) {
if (jami === 0) {
return 0;
}
return Math.round((qism * 100) / jami);
}
function jamgarmaFoizi(daromad, xarajat) {
return foizHisobla(daromad - xarajat, daromad);
}
function jamgarmaXabari(foiz) {
if (foiz < 20) {
return `⚠️ Jamg'arma ${foiz}% — 20% dan kam`;
}
return `✅ Jamg'arma ${foiz}%`;
}
const foiz = jamgarmaFoizi(7_500_000, 4_985_000);
console.log(foiz); // 34
console.log(jamgarmaXabari(foiz)); // ✅ Jamg'arma 34%
console.log(jamgarmaXabari(jamgarmaFoizi(7_500_000, 6_400_000)));Konsolda:
34
✅ Jamg'arma 34%
⚠️ Jamg'arma 15% — 20% dan kamIkkala funksiya toza. dasturniIshgaTushir ga bitta qator qo'shiladi: console.log(jamgarmaXabari(jamgarmaFoizi(daromad, xarajat)));. Xarajat daromaddan oshsa, foiz manfiy — u ham 20 dan kam, ogohlantirish chiqadi.
3-mashq (qiyin): "Agar ... bo'lsa?"
Aziz 3 200 000 so'mlik noutbuk olmoqchi. Shu oy olsa, qancha qoladi? Asl ro'yxatga tegmasdan, xarid qo'shilgan yangi ro'yxat bilan hisoblang.
xarajatQosh(royxat, yangi) ni yozing: yozuv to'g'ri bo'lsa (xatoSababi bo'yicha) — yangi massiv, noto'g'ri bo'lsa — ro'yxatning nusxasi. Ikki holatda qolgan pulni chiqaring va asl massiv uzunligi o'zgarmaganini ko'rsating.
Ishora: massivga yozuvni spread bilan qo'shish — [...royxat, yangi] (Spread va rest).
Yechim
function xatoSababi(summa) {
if (typeof summa !== "number") {
return "summa son emas";
}
if (!Number.isInteger(summa)) {
return "summa butun son emas";
}
if (summa <= 0) {
return "summa musbat emas";
}
return null;
}
function jamiHisobla(royxat) {
let jami = 0;
for (const { summa } of royxat) {
jami += summa;
}
return jami;
}
function xarajatQosh(royxat, yangi) {
if (xatoSababi(yangi.summa) !== null) {
return [...royxat];
}
return [...royxat, yangi];
}
const daromad = 7_500_000;
const xarajatlar = [
{ toifa: "ijara", summa: 2_500_000 },
{ toifa: "ovqat", summa: 1_620_000 },
];
const noutbuk = { toifa: "texnika", summa: 3_200_000 };
const reja = xarajatQosh(xarajatlar, noutbuk);
console.log(daromad - jamiHisobla(xarajatlar)); // 3380000
console.log(daromad - jamiHisobla(reja)); // 180000
console.log(xarajatlar.length, reja.length); // 2 3Noutbuk olinsa, atigi 180 000 so'm qoladi — xaridni keyingi oyga qoldirgan ma'qul. xarajatlar.length hali ham 2: [...royxat, yangi] yangi massiv yaratdi, asliga push qilinmadi. Noto'g'ri yozuvda ham [...royxat] — funksiya doim yangi massiv qaytaradi.
4-mashq: Portfolio qadami — loyiha kartasi
Byudjet — birinchi to'liq dasturingiz. Uni portfolio'dagi "Loyihalar" sahifasiga qo'shing.
kurs/portfoliodasayt/loyihalar/index.htmlni oching.<div class="loyihalar">ichiga, mavjud kartalar qatoriga yangiarticleqo'shing. Tuzilmasi boshqa kartalardagidek bo'lsin:h2,time, tavsif va havola (Yakuniy loyiha: portfolio).- Havola — GitHub'dagi
08/byudjetpapkasiga. npm run checkbilan tekshiring va commit qiling:Loyihalar: byudjet dasturi kartasini qo'sh.git pushdan keyin sayt GitHub Actions orqali o'zi yangilanadi (Avtomatik deploy).
Yechim
<article>
<h2>Oylik byudjet — konsol dasturi</h2>
<p><time datetime="2026-10">2026-yil oktabr</time></p>
<p>
Node.js dasturi: xarajatlarni tekshiradi, toifa bo'yicha
yig'indi va ulushni hisoblaydi, limitdan oshganda ogohlantiradi.
</p>
<ul>
<li>
<a
href="https://github.com/login/mashqlar/tree/main/08/byudjet"
>Kodni GitHub'da ko'rish</a>
</li>
</ul>
</article>login — GitHub nomingiz. Boshqa kartalarda ul ga role="list" qo'shgan bo'lsangiz, bunga ham qo'shing. .loyihalar > article selektori yangi kartani ham o'zi bezaydi. Rasm o'rniga keyinroq terminal skrinshotini qo'yishingiz mumkin.
15. Real ishda
- Hisobotlar hamma joyda. Bank ilovasidagi "xarajatlar tahlili", do'konning kunlik savdo hisoboti — hammasi shu sxema: ma'lumot → tekshirish → guruhlash → foiz → chiqarish. Farqi: ma'lumot bazadan keladi, natija veb-sahifada chiziladi.
- Ma'lumotni tekshirish — backend dasturchining kundalik ishi. Foydalanuvchi formaga istagan narsani yozadi, server esa hisobdan oldin uni tekshiradi. Bu xavfsizlik ham: tekshirilmagan qiymat hisobni buzadi.
- Avtomatik testlar. Bugun har bosqichni
console.logbilan qo'lda tekshirdingiz. Real loyihada bu tekshiruvlar avtomatik test bo'lib, bitta buyruq bilan ishlaydi. Testlarni kursda keyinroq o'rganamiz — hozir bilish shart emas. Toza funksiya esa testga eng qulay. - Intervyuda "buyurtmalarni toifa bo'yicha guruhlang" — odatiy junior savoli.
08-qism yakuni
Tabriklaymiz — "JavaScript asoslari" qismi tugadi! Bugun siz dastur yozdingiz: ma'lumotni qabul qiladi, tekshiradi, hisoblaydi va odam tushunadigan hisobot beradi. Qism boshida bitta console.log yozgan edingiz — endi GitHub'da 170 qatorga yaqin ishlaydigan loyiha turibdi.
Dasturning bitta kamchiligi bor: u faqat terminalda yashaydi. Keyingi qismda JavaScript'ni brauzerga olib chiqamiz: tugma, forma, ekranda chiziladigan ro'yxat. Obyektlar massivi, toza funksiya va spread u yerda har qadamda kerak bo'ladi.
Xulosa
- Katta vazifa kichik funksiyalarga bo'linadi: har biri bitta ish, nomi shu ishni aytadi.
- Hisob-kitob — toza funksiyalarda,
console— bitta "ofitsiant" funksiyada. - Ma'lumot hisobdan oldin tekshiriladi:
typeof,Number.isInteger, musbatlik; buzuq yozuv ogohlantirish bilan o'tkaziladi. - Obyekt-hisoblagich:
(obyekt[kalit] ?? 0) + qiymat. - Pul — butun so'mda, foiz —
Math.round((qism * 100) / jami), nolga bo'lish himoyalangan. - Asl ma'lumot spread bilan himoyalanadi:
{ ...yozuv },[...royxat, yangi].
Keyingi dars: Brauzer muhiti: window, document va skript yuklanishi — 09-qism boshlanadi: JavaScript sahifaga qanday ulanishini va brauzer unga qanday imkoniyatlar berishini ko'ramiz.
Manbalar
- MDN: "String.prototype.padStart()", "String.prototype.padEnd()" — developer.mozilla.org
- MDN: "Number.isInteger()", "Nullish coalescing operator (??)" — developer.mozilla.org
- Node.js: "console.table()" — nodejs.org/api/console.html
- Node.js: "Debugging Node.js" — nodejs.org/en/learn/getting-started/debugging
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!