Mundarija (34)
- Bu darsda
- 1. Nega bu kerak?
- 2. Funksiya bitta ish qiladi
- 2.1 Bitta ish nima?
- 2.2 Bir daraja abstraksiya
- 3. Erta qaytish
- 3.1 Ichma-ich shartlar
- 3.2 Avval xatolar, keyin asosiy yo'l
- 4. Parametrlar va yon ta'sir
- 4.1 Parametrlar soni
- 4.2 Flag argument
- 4.3 Yashirin yon ta'sir
- 5. Sehrli raqamlar va satrlar
- 6. Izohlar
- 6.1 Izoh turlari
- 6.2 "Nima" izohi — o'chiriladi
- 6.3 "Nega" izohi — qo'shiladi
- 6.4 Izohlangan kod
- 7. Fayl tuzilmasi va formatlash
- 7.1 Fayl — gazeta kabi
- 7.2 Formatlash — mashinaga
- 8. Ko'p uchraydigan xatolar
- 8.1 Haddan tashqari mayda bo'lish
- 8.2 Izoh — yomon kodni oqlash uchun
- 8.3 Eskirgan izoh
- 8.4 Ajratishda tartibni o'zgartirish
- 9. Mashqlar
- 1-mashq (oson): "Nima" va "nega"
- 2-mashq (o'rta): Erta qaytish
- 3-mashq (qiyin): Bo'ling va flag'dan qutuling
- 4-mashq: Vazifalar qadami — funksiyalarni bo'lish va izohlarni tozalash
- 10. Real ishda
- Xulosa
- Manbalar
Toza kod: funksiyalar, izohlar va tuzilma — bitta ish, erta qaytish va "nega" izohi
Qisqacha: Toza funksiya bitta ish qiladi va nomi shu ishni aytadi. Shartlar ichma-ich emas — erta qaytish (guard clause) bilan yoziladi. Parametrlar kam (ko'p bo'lsa — sozlama obyekti),
true/falsebilan xulqni almashtiruvchi "flag argument" yo'q. Sehrli raqam o'rniga nomli o'zgarmas (KUTISH_MS). Izoh kod nima qilishini takrorlamaydi — nega shunday yozilganini tushuntiradi.
Bu darsda
- Uzun funksiyani "bitta ish — bitta funksiya" qoidasi bilan bo'la olasiz.
- Ichma-ich shartlarni erta qaytish bilan tekislay olasiz.
- Parametrlar ko'payganda, flag argument va yashirin yon ta'sirda nima qilishni bilasiz.
- "Nima" izohini o'chirib, "nega" izohini yoza olasiz; izoh turlarini farqlaysiz.
vazifalarning eng uzun funksiyalarini xulqni o'zgartirmasdan bo'lasiz.
Oldin bilishingiz kerak: Toza kod: nomlash, return va erta qaytish, Pure funksiya va side effect, Parametrda destructuring va options obyekti.
1. Nega bu kerak?
O'tgan darsda nomlarni tozaladik. Endi Sardorga yangi topshiriq: "Server bilan sinxron paytida, agar server ro'yxatni bilmasa, ekranda e'lon chiqsin". U asosiy.js dagi sinxronla() funksiyasini ochadi. Funksiya 40 qatordan iborat: kutilayotgan yozuvlarni tekshiradi, eski so'rovni bekor qiladi, internetni tekshiradi, serverdan ro'yxat oladi, kerak bo'lsa yuboradi, javobni tekshiradi, solishtiradi, holatni yozadi, xatolarni ushlaydi.
Kerakli joyni topish uchun Sardor hammasini o'qib chiqishi kerak. Bitta joyni o'zgartirsa, qo'shni ishni buzib qo'ymaydimi — bilmaydi.
Uzun funksiya — sarlavhasiz, paragrafsiz o'n sahifali bob kabi: ichida hamma narsa bor, lekin hech narsani topib bo'lmaydi. Bu darsda funksiyani nomli "bob"larga bo'lamiz, keyin izohlarga o'tamiz.
2. Funksiya bitta ish qiladi
2.1 Bitta ish nima?
«Bahor»da buyurtma yopilganda chek chiqadi. O'tgan darsda kelishgan edik: bundan keyingi mustaqil misollarda nomlar inglizcha, izohlar o'zbekcha. closeOrder — "buyurtmani yop", order — buyurtma, item — undagi bitta qator, price — narx, qty (quantity) — soni. Sardorning birinchi varianti:
function closeOrder(order) {
let total = 0;
for (const item of order) {
total += item.price * item.qty;
}
if (total >= 200000) {
total = (total * 90) / 100;
}
console.log("— «Bahor» —");
for (const item of order) {
console.log(`${item.name} × ${item.qty}`);
}
console.log(`Jami: ${total} so'm`);
}
closeOrder([
{ name: "Osh", price: 35000, qty: 4 },
{ name: "Manti", price: 30000, qty: 2 },
{ name: "Ko'k choy", price: 5000, qty: 4 },
]);Konsolda:
— «Bahor» —
Osh × 4
Manti × 2
Ko'k choy × 4
Jami: 198000 so'mBu funksiya nima qiladi? Javobni "va" bilan aytishga to'g'ri keladi: summani hisoblaydi va chegirma beradi va chek chiqaradi. Har "va" — alohida ish. Oddiy sinov shu: funksiya ishini bitta gapda, "va"siz ayta olmasangiz — u bir nechta ish qilyapti.
Endi har ishni o'z funksiyasiga ajratamiz: calculateTotal — "jamini hisobla", applyDiscount — "chegirmani qo'lla", printReceipt — "chekni chiqar". Nomlar o'zi aytib turibdi — izoh shart emas:
const DISCOUNT_THRESHOLD = 200000; // so'm
const DISCOUNT_PERCENT = 10;
function calculateTotal(order) {
return order.reduce(
(total, item) => total + item.price * item.qty,
0,
);
}
function applyDiscount(amount) {
if (amount < DISCOUNT_THRESHOLD) {
return amount;
}
return (amount * (100 - DISCOUNT_PERCENT)) / 100;
}
function printReceipt(order, amount) {
console.log("— «Bahor» —");
for (const item of order) {
console.log(`${item.name} × ${item.qty}`);
}
console.log(`Jami: ${amount} so'm`);
}
function closeOrder(order) {
const amount = applyDiscount(calculateTotal(order));
printReceipt(order, amount);
}
closeOrder([
{ name: "Osh", price: 35000, qty: 4 },
{ name: "Manti", price: 30000, qty: 2 },
{ name: "Ko'k choy", price: 5000, qty: 4 },
]);Konsolda:
— «Bahor» —
Osh × 4
Manti × 2
Ko'k choy × 4
Jami: 198000 so'mNatija bir xil — xulq o'zgarmadi. Lekin endi closeOrder ni o'qisangiz, u mundarija kabi: "summani hisobla, chegirma ber, chek chiqar". Tafsilot kerak bo'lsa — tegishli funksiyaga kirasiz. Jasur aka "chegirma 15% bo'lsin" desa, Sardor faqat DISCOUNT_PERCENT ni o'zgartiradi va chek kodiga tegmaydi.
Yana bir yutuq: calculateTotal va applyDiscount — toza funksiyalar (Pure funksiya va side effect). Ular ekranga hech narsa yozmaydi, faqat qiymat qaytaradi. Bunday funksiyani tekshirish qulay — keyingi darsda aynan shularga birinchi avtomatik testni yozamiz.
2.2 Bir daraja abstraksiya
Ikkinchi variantdagi closeOrder ichida faqat "katta" qadamlar bor. Unda item.price * item.qty kabi mayda hisob yo'q. Buni bir daraja abstraksiya deyishadi. Abstraksiya — tafsilotni yashirib, faqat "nima qilinadi"ni ko'rsatish; "bir daraja" — funksiya ichidagi hamma qatorlar bir xil "balandlikda" gapiradi. Rahbar "hisobotni tayyorla, Jasur akaga yubor" deydi — u Excel formulasini aytmaydi.
Funksiya qancha uzun bo'lishi kerak? Aniq raqam yo'q. Amaliy mo'ljal: ekranga sig'sin (taxminan 20 qatorgacha) va ishini bir gapda ayta olasiz. vazifalar dagi sinxronla() 40 qator edi — Vazifalar qadamida uni bo'lamiz.
Tekshirib ko'ring:
function saveBookingAndNotify(booking)("bronni saqla va xabar yubor") — nomning o'zi nima haqida signal beradi?
Javob
Nomda "va" (And) bor — demak, funksiya ikki ish qiladi. Ularni ajrating: saveBooking(booking) va notifyGuest(booking), chaqiruvchi esa ikkalasini ketma-ket chaqiradi. Shunda saqlashni xabarsiz ham ishlatish mumkin bo'ladi (masalan, import paytida).
3. Erta qaytish
3.1 Ichma-ich shartlar
return va erta qaytish darsida ko'rgan edik: return funksiyani darhol tugatadi. Bron formasini tekshiradigan funksiyani ikki xil yozamiz. bookingError — "bron xatosi": xato matnini yoki null (xato yo'q) qaytaradi; guests — mehmonlar soni, hour — soat. Avval ichma-ich:
const MAX_GUESTS = 20;
const BOOKING_START = 10; // soat
const BOOKING_END = 22;
function bookingError(booking) {
if (booking.guests >= 1) {
if (booking.guests <= MAX_GUESTS) {
if (
booking.hour >= BOOKING_START &&
booking.hour <= BOOKING_END
) {
return null;
} else {
return "Bron 10:00–22:00 oralig'ida";
}
} else {
return `Ko'pi bilan ${MAX_GUESTS} kishi`;
}
} else {
return "Kamida 1 kishi";
}
}
console.log(bookingError({ guests: 25, hour: 12 }));Konsolda:
Ko'pi bilan 20 kishiKod o'ngga qarab "o'q uchi" shaklida o'sadi. Har else o'zining if idan uzoqda: "Kamida 1 kishi" qaysi shartga tegishli ekanini topish uchun ko'z yuqoriga qaytadi.
3.2 Avval xatolar, keyin asosiy yo'l
Endi har xato holatni boshida tekshirib, darhol qaytamiz. Bunday tekshiruv himoya sharti (guard clause) deyiladi — eshik oldidagi qo'riqchi kabi: mos kelmaganni ichkariga kiritmaydi.
const MAX_GUESTS = 20;
const BOOKING_START = 10; // soat
const BOOKING_END = 22;
function bookingError(booking) {
if (booking.guests < 1) {
return "Kamida 1 kishi";
}
if (booking.guests > MAX_GUESTS) {
return `Ko'pi bilan ${MAX_GUESTS} kishi`;
}
if (booking.hour < BOOKING_START || booking.hour > BOOKING_END) {
return "Bron 10:00–22:00 oralig'ida";
}
return null;
}
console.log(bookingError({ guests: 25, hour: 12 }));
console.log(bookingError({ guests: 4, hour: 19 }));Konsolda:
Ko'pi bilan 20 kishi
nullHar shart va uning javobi yonma-yon. else yo'q, chekinish bir pog'ona. Funksiyaning oxirgi qatori — "hammasi joyida" yo'li. Quyidagi vizualda ikkala chaqiruv qadamma-qadam bajariladi — qaysi return funksiyani tugatganiga qarang:
vazifalar da bu usul hamma joyda bor. Masalan, sinxronla() boshida: if (kutilmoqda > 0) { return; } va if (!navigator.onLine) { … return; }.
Tekshirib ko'ring: Himoya shartlarining tartibi muhimmi?
bookingError({ guests: 0, hour: 5 })da ikki xato bor — qaysi biri qaytadi?
Javob
Muhim. Birinchi mos kelgan shart g'olib: "Kamida 1 kishi" qaytadi, soat tekshirilmaydi ham. Shuning uchun eng asosiy (yoki foydalanuvchi uchun eng tushunarli) xatoni birinchi qo'ying. Hamma xatolarni birdaniga ko'rsatish kerak bo'lsa — qaytarish o'rniga ularni massivga yig'ish kerak.
4. Parametrlar va yon ta'sir
4.1 Parametrlar soni
Parametr qancha ko'p bo'lsa, chaqiruvni o'qish shuncha qiyin (createBooking — "bron yarat"):
createBooking("Dilshod aka", 4, "2026-10-05", 19, true, false);true nima? false nima? Tartibni adashtirsangiz, xato jimgina o'tib ketadi. Mo'ljal: 0–2 parametr — ideal, 3 — chidasa bo'ladi. Undan ko'p bo'lsa, options obyekti ishlating — har qiymatning nomi bor, tartib ahamiyatsiz:
createBooking({
guest: "Dilshod aka",
guests: 4,
date: "2026-10-05",
hour: 19,
onTerrace: true, // ayvonda
});vazifalar da shunday: apiKlient({ asosiyUrl, kalit, muvaffaqiyatsiz }).
4.2 Flag argument
Flag argument — funksiyaning ish turini almashtiradigan true/false parametr:
printReceipt(order, amount, true); // true — qisqa chekmi?Chaqiruvni o'qiganda true hech narsa aytmaydi. Aslida bu funksiya ichida ikki funksiya yashiringan: if (short) { … } else { … }. Ularni ajrating — printShortReceipt(order) ("qisqa chekni chiqar") va printReceipt(order, amount). Har birining nomi o'z ishini aytadi.
Sozlama obyekti ichidagi nomli mantiqiy qiymat esa boshqa gap: apiKlient({ muvaffaqiyatsiz: true }) da nom ko'rinib turibdi va u funksiyani ikkiga bo'lmaydi — faqat manzilga parametr qo'shadi.
4.3 Yashirin yon ta'sir
Yon ta'sir (side effect) — funksiya qiymat qaytarishdan tashqari qiladigan ish: faylga yozish, ekranni o'zgartirish, global o'zgaruvchiga tegish. Yon ta'sirning o'zi yomon emas — usiz dastur hech narsa qilmaydi. Yomoni — yashirin yon ta'sir: validate(booking) ("tekshir") nomli funksiya tekshirish bilan birga bronni saqlab ham qo'ysa.
Foydali qoida: funksiya yo so'raydi (qiymat qaytaradi, hech narsani o'zgartirmaydi), yo buyuradi (o'zgartiradi). Ikkalasini birga emas. Bu qoida "buyruq va so'rovni ajratish" (command-query separation) deyiladi. holat.js aynan shunday tuzilgan:
// So'rovlar: faqat qiymat qaytaradi
export function xatoniTop(matn, vazifalar, ozId) { … }
export function korinadiganlar() { … }
// O'zgartiruvchilar
export function vazifaQosh(matn) { … }
export function vazifaniOchir(id) { … }Tekshirib ko'ring:
function checkBooking(booking)("bronni tekshir") xato bo'lsafalseqaytaradi, xato bo'lmasa bronni bazaga yozibtrueqaytaradi. Nima muammo?
Javob
Nom "tekshir" deydi, lekin funksiya yozadi ham — yashirin yon ta'sir. Kimdir formani "faqat tekshirib ko'rish" uchun chaqirsa, bron bazaga tushib qoladi. Ikkiga bo'ling: bookingError(booking) (so'rov) va saveBooking(booking) (buyruq).
5. Sehrli raqamlar va satrlar
Kodda izohsiz turgan 8000, 0.9, "tahrir-maydon" — sehrli qiymat (magic number). U qayerdan kelgani va nimani anglatishi noma'lum. api.js ning birinchi qatorlariga qarang:
// api.js — server bilan gaplashadigan yagona joy
const KUTISH_MS = 8000;8000 o'rniga KUTISH_MS — "kutish, millisekundda": birlik nomning o'zida (_MS), qiymat o'zgarsa — bitta joyda o'zgaradi.
vazifa.js da yana bir yaxshi misol bor:
// index.html dagi maxlength bilan bir xil bo'lsin
static MAKS_UZUNLIK = 100;Bu yerdagi izoh negani aytadi: raqam HTML'dagi boshqa raqam bilan bog'langan, biri o'zgarsa — ikkinchisi ham.
vazifalar da sehrli qiymatlar hali qolgan: "tahrir-maydon" satri ikki modulda olti marta takrorlanadi, eksport paketining versiyasi 1 uch joyda yozilgan. Ularni Code smell va refactoring darsida "kod hidi" sifatida topib tuzatamiz.
Hamma raqam ham sehrli emas. 0 va 1 (reduce boshlang'ich qiymati, indeks), 100 foizda, 2 "ikki baravar" ma'nosida — o'zi tushunarli. Savol bering: "Bu raqamni ko'rgan odam uning ma'nosini so'raydimi?" So'rasa — nom bering.
6. Izohlar
6.1 Izoh turlari
| Tur | Misol | Kerakmi |
|---|---|---|
| "Nima" izohi | // massivni aylanamiz |
yo'q — kod o'zi aytadi |
| "Nega" izohi | // Matn oldindan olinadi: o'chirilgandan keyin vazifa yo'q |
ha — koddan ko'rinmaydi |
| Ogohlantirish | // index.html dagi maxlength bilan bir xil bo'lsin |
ha |
TODO |
// TODO: bron 30 kundan keyinga bo'lmasin |
qisqa muddatga |
| Hujjat izohi (JSDoc) | /** @param {string} matn */ |
eksport qilingan funksiyada |
Kod nima qilishini kodning o'zi aytadi — nomlar va tuzilma orqali. Kod nega aynan shunday yozilganini esa aytolmaydi: qaysi xato bo'lgani, qaysi muqobil sinab ko'rilib rad etilgani, qaysi chegara hisobga olingani. Izohning joyi — shu yerda.
Hujjat izohi — /** … */ ichida funksiyaning parametrlari va natijasini maxsus belgilar (@param, @returns) bilan yozish. Uni muharrir o'qiydi va funksiyani chaqirganda maslahat ko'rsatadi. Buni JSDoc va // @ts-check darsida to'liq o'rganamiz, hozir bilish shart emas.
6.2 "Nima" izohi — o'chiriladi
asosiy.js da shunday qatorlar bor edi:
// Internet uzildi yoki qaytdi
addEventListener("offline", () => { … });
addEventListener("online", () => sinxronla());
// Boshqa tablardagi o'zgarishlar
tingla(boshqaTabdanYangila);"offline" va "online" — hodisa nomlari "internet uzildi yoki qaytdi" deb turibdi. boshqaTabdanYangila nomi ham o'zini tushuntiradi. Izoh shunchaki takrorlaydi. Takror izoh zararli: kod o'zgarsa, izoh o'zgarmay qoladi va yolg'on gapira boshlaydi.
render.js da esa 09-qismdan o'quv izohi qolib ketgan edi: // querySelector — royxat'ning metodi: uni nuqta bilan chaqiramiz. Dars uchun foydali, ishlaydigan loyihada — ortiqcha.
6.3 "Nega" izohi — qo'shiladi
render.js dagi kichik funksiya:
// Bir xil matnni qayta yozish ham DOM o'zgarishi: jonli hudud
// (#hisob, #aloqa) uni ekran o'quvchiga qayta o'qib berishi mumkin
function matnniYoz(element, matn) {
if (element.textContent !== matn) {
element.textContent = matn;
}
}Izohsiz Sardor o'ylardi: "Bu if ortiqcha, to'g'ridan-to'g'ri yozib qo'yaman" — va Malika (ko'zi ojiz mehmon, NVDA bilan ishlaydi) har chizishda bir xil e'lonni qayta-qayta eshitardi. Izoh kelajakdagi "tozalovchi"ni xatodan saqlaydi.
6.4 Izohlangan kod
// const doneTasks = tasks.filter((t) => t.done);
// console.log(doneTasks);Bunday "o'chirilgan, lekin qoldirilgan" kodni o'chiring. Uni hech kim qayta yoqmaydi, lekin har o'quvchi "bu nega turibdi, muhimmi?" deb to'xtaydi. Eski kod kerak bo'lsa — git eslab qoladi (Tarixni o'qish: git log).
Tekshirib ko'ring: Quyidagi izoh "nima"mi yoki "nega"mi?
// Qiymat bosilgan paytda olinadi: serverga aynan shu yuboriladi
Javob
"Nega". U const bajarildi = !vazifaniTop(id).bajarildi; qatori nega serverdaBajar dan oldin turganini tushuntiradi: ekrandagi o'zgarishdan keyin olinsa, qiymat teskari bo'lib qolardi. Koddan buni bilib bo'lmaydi.
7. Fayl tuzilmasi va formatlash
7.1 Fayl — gazeta kabi
Gazetada sarlavha tepada, tafsilot pastda. Fayl ham shunday o'qilsin: yuqorida importlar va o'zgarmaslar, keyin yordamchi funksiyalar, keyin asosiy (eksport qilinadigan) funksiyalar. asosiy.js da har bo'lim boshida qisqa izoh-sarlavha bor: // Hodisalar: har joyda bitta tinglovchi.
Bog'liq qatorlar birga turadi, bo'sh qator — "paragraf" chegarasi. Bitta funksiya ichida ham: tayyorlash, asosiy ish, natija — orasida bo'sh qator.
7.2 Formatlash — mashinaga
Chekinish 2 bo'sh joymi yoki 4? Bu savolda to'g'ri javob yo'q — muhimi, butun loyiha bir xil bo'lsin. Jamoalar bu bahsni vositaga topshiradi: Prettier kodni avtomatik formatlaydi (ESLint va Prettier darsida vazifalar ga o'rnatamiz). Ungacha: atrofdagi kod qanday yozilgan bo'lsa, shunday yozing.
Funksiya o'lchami haqidagi qoidalar ortida uchta mashhur tamoyil turadi: DRY (takrorlama), KISS (sodda qil), YAGNI (hozir kerak bo'lmagan narsani yozma). Ularni arxitektura qismida (Asosiy tamoyillar) batafsil ko'ramiz, hozir bilish shart emas.
8. Ko'p uchraydigan xatolar
8.1 Haddan tashqari mayda bo'lish
Har qatorni funksiyaga aylantirish ham xato: function addOne(n) { return n + 1; }. O'quvchi o'nlab fayl va funksiyalar orasida sakrab yuradi. Funksiya nomli fikr bo'lsin, bitta qatorning boshqa nomi emas.
8.2 Izoh — yomon kodni oqlash uchun
// x — foydalanuvchining yoshi izohini yozishdan oldin x ni age ga o'zgartiring. Izoh nomlash xatosini yamaydi, tuzatmaydi.
8.3 Eskirgan izoh
Kod o'zgardi, izoh qoldi: // 10% chegirma yonida endi DISCOUNT_PERCENT = 15. Kodni o'zgartirganda uning ustidagi izohni ham o'qing.
8.4 Ajratishda tartibni o'zgartirish
Funksiyani bo'lganda chaqiruvlar tartibi o'zgarib qolsa, xulq ham o'zgaradi. katakniAlmashtir da bajarildi qiymati ekrandagi o'zgarishdan oldin olinadi; keyinga o'tkazilsa — serverga teskari qiymat ketadi. Refaktorda har qatorni "ko'chiraman", "o'zgartirmayman" deb o'ylang.
9. Mashqlar
1-mashq (oson): "Nima" va "nega"
Qaysi izoh qoladi, qaysi biri o'chadi? Nega?
// Narxni soniga ko'paytiramiz
const amount = price * qty;
// Mehmon narxni telefonda ko'radi: brauzer "75,000" chiqarishi
// mumkin, shuning uchun o'z formatimiz
const text = formatSom(amount);
// i ni oshiramiz
i++;Yechim
Birinchi va uchinchi izoh — "nima": kod o'zi aytib turibdi, o'chiriladi. Ikkinchisi — "nega": u Intl.NumberFormat darsidagi Chrome muammosini eslatadi (formatSom — o'sha darsdagi somYoz ning inglizcha nomi) va kelajakdagi o'quvchini toLocaleString ga "soddalashtirish"dan saqlaydi. U qoladi.
2-mashq (o'rta): Erta qaytish
Quyidagi funksiyani himoya shartlari bilan qayta yozing. Natija o'zgarmasin. orderError — "buyurtma xatosi", dish — taom, dish.available — taom bugun bormi, dish.stock — nechta porsiya qolgani.
function orderError(dish, qty) {
if (dish !== undefined) {
if (dish.available) {
if (qty <= dish.stock) {
return null;
} else {
return `Faqat ${dish.stock} porsiya qoldi`;
}
} else {
return "Bugun yo'q";
}
} else {
return "Bunday taom yo'q";
}
}
const manti = { name: "Manti", available: true, stock: 3 };
console.log(orderError(manti, 5)); // Faqat 3 porsiya qoldi
console.log(orderError(undefined, 1)); // Bunday taom yo'q
console.log(orderError(manti, 2)); // nullYechim
function orderError(dish, qty) {
if (dish === undefined) {
return "Bunday taom yo'q";
}
if (!dish.available) {
return "Bugun yo'q";
}
if (qty > dish.stock) {
return `Faqat ${dish.stock} porsiya qoldi`;
}
return null;
}
const manti = { name: "Manti", available: true, stock: 3 };
console.log(orderError(manti, 5)); // Faqat 3 porsiya qoldi
console.log(orderError(undefined, 1)); // Bunday taom yo'q
console.log(orderError(manti, 2)); // nullHar shartni teskarisiga aylantirdik: dish !== undefined → dish === undefined, qty <= dish.stock → qty > dish.stock. Teskari shartda <= ning juftini adashtirmang: <= ning teskarisi >, >= emas.
3-mashq (qiyin): Bo'ling va flag'dan qutuling
Funksiya ikki ish qiladi va flag argument oladi. report — hisobot, orders — buyurtmalar, short — qisqami, revenue — tushum. Uni uchta funksiyaga bo'ling: kunlik tushumni hisoblash (toza funksiya), to'liq hisobot va qisqa hisobot. Konsol chiqishi o'zgarmasin.
function report(orders, short) {
let revenue = 0;
for (const order of orders) {
revenue += order.amount;
}
if (short) {
console.log(`Tushum: ${revenue}`);
} else {
console.log(`Buyurtmalar: ${orders.length} ta`);
console.log(`Tushum: ${revenue} so'm`);
}
}
const today = [{ amount: 70000 }, { amount: 198000 }];
report(today, true);
report(today, false);Konsolda:
Tushum: 268000
Buyurtmalar: 2 ta
Tushum: 268000 so'mYechim
function calculateRevenue(orders) {
return orders.reduce((total, o) => total + o.amount, 0);
}
function printShortReport(orders) {
console.log(`Tushum: ${calculateRevenue(orders)}`);
}
function printReport(orders) {
console.log(`Buyurtmalar: ${orders.length} ta`);
console.log(`Tushum: ${calculateRevenue(orders)} so'm`);
}
const today = [{ amount: 70000 }, { amount: 198000 }];
printShortReport(today);
printReport(today);Konsolda:
Tushum: 268000
Buyurtmalar: 2 ta
Tushum: 268000 so'mtrue/false o'rniga endi chaqiruvning o'zi gapiradi: printShortReport(today) — "qisqa hisobotni chiqar". Hisob bitta joyda (calculateRevenue) — u toza, uni test qilish oson. Ikki chiqaruvchi funksiya — fe'l (print) bilan, chunki ular ekranga yozadi. Bir qatorli arrow'dagi o — joiz: to'plam nomi orders. Qisqa hisobotda "so'm" yo'qligi ataylab saqlandi: refaktor xulqni o'zgartirmaydi, hatto u g'alati bo'lsa ham. Uni tuzatish — alohida, ongli qaror.
4-mashq: Vazifalar qadami — funksiyalarni bo'lish va izohlarni tozalash
Branch: refactor/funksiyalar-izohlar. Ilovaning xulqi o'zgarmaydi.
Funksiyalar. Eng uzunlari bo'linadi, har yangi funksiya — bitta ish:
| Oldin | Keyin |
|---|---|
asosiy.js ro'yxat click tinglovchisi — 42 qator, switch ichida ikki optimistik amal |
katakniAlmashtir(id, zaxira), qatorniOchir(id, zaxira); har case — bitta chaqiruv |
forma submit tinglovchisi — 18 qator |
yangiVazifaniQosh(); tinglovchida preventDefault() va chaqiruv |
importTugma tinglovchisi — 19 qator |
importQil(); tinglovchi — () => importQil() |
| Oldin | Keyin |
|---|---|
sinxronla() — 40 qator: GET, versiya 0 → PUT, tekshirish, solishtirish, holat |
serverRoyxatiniOl(sozlama) va qisqargan sinxronla() |
api.js sorovYubor() — 40 qator: sozlama, tarmoq, JSON, status |
sorovniTayyorla(sozlama), javobniOqi(javob, matn); sorovYubor — faqat tarmoq |
render.js render() — 17 qator, 5 ish |
boshXabarniYoz(), filtrTugmalariniYoz(), hisobniYoz(); render() — qadamlar ro'yxati |
sinxronla() dan ajralgan yangi funksiya:
// Server kalitni bilmasa (versiya 0) — o'zimizdagi ro'yxat ketadi.
// Server javobi ham import kabi tekshiriladi
async function serverRoyxatiniOl(sozlama) {
let { vazifalar, versiya } = await api.royxat(sozlama);
if (versiya === 0) {
const joriy = holat.vazifalar.toJSON();
({ vazifalar } = await api.almashtir(joriy, sozlama));
}
return paketniOqi(eksportMatni(vazifalar));
}sinxronla() ichida endi bitta qator va bitta "nega" izohi:
const toza = await serverRoyxatiniOl({ signal: pult.signal });
// Farq bo'lmasa — saqlash, tarqatish va chizish shart emas
if (eksportMatni(toza) !== eksportMatni(holat.vazifalar)) {
royxatniYangila(toza);
}render() — mundarija:
export function render() {
royxat.replaceChildren(...korinadiganlar().map(qatorYasa));
// Ro'yxatdan keyin: bosh xabar qatorlar soniga qaraydi
boshXabarniYoz();
filtrTugmalariniYoz();
hisobniYoz();
teglarniYoz();
aloqaniYoz();
}Diagrammada render() va uning qadamlari. Tartibga qarang: bosh xabar faqat ro'yxat chizilgandan keyin yoziladi — izoh shuni aytadi:
flowchart LR
R["render()"] --> A["1. ro'yxat qatorlari"]
R --> B["2. boshXabarniYoz"]
R --> C["3. filtrTugmalariniYoz"]
R --> D["4. hisobniYoz"]
R --> E["5. teglarniYoz"]
R --> F["6. aloqaniYoz"]
A -. "qatorlar soni" .-> Bswitch ning har case i endi bitta chaqiruv:
switch (amal) {
case "almashtir":
katakniAlmashtir(id, zaxira);
break;
case "ochir":
qatorniOchir(id, zaxira);
break;Chaqiruvlar tartibi o'zgarmadi. AbortSignal.timeout hali ham fetch dan oldin yaratiladi, toJSON() GET javobidan keyin olinadi. katakniAlmashtir da qiymat ekrandagi o'zgarishdan oldin olinadi — "Ko'p uchraydigan xatolar" bo'limidagi tuzoq aynan shu.
Izohlar. O'chirildi ("nima"ni takrorlaydi): // Quyidagi beshtasi eksport qilinmaydi… (royxat.js — export yo'qligi o'zi aytadi), // querySelector — royxat'ning metodi… (render.js, o'quv izohi), // Internet uzildi yoki qaytdi va // Boshqa tablardagi o'zgarishlar (asosiy.js).
Qo'shildi ("nega"):
matnniYoz— bir xil matnni qayta yozish jonli hududni qayta o'qitishi mumkin;eksportMatni— massiv ko'rinishidagi ikkinchi argument yangi maydonni eksportga sizdirmaydi;royxatniUla— tahrirdagi vazifani boshqa tab yoki server o'chirgan bo'lishi mumkin;boshqaTabdanYangila— nega saqlamaymiz va tarqatmaymiz (aks-sado);serverdaBajar—oldinginusxa nega kerak;katakniAlmashtir,qatorniOchir— qiymat nega oldindan olinadi;sorovYubor— javob tanasi nega hamtryichida;render()— bosh xabar nega ro'yxatdan keyin.
Mana ulardan biri:
// Boshqa tab o'zgartirdi: ro'yxat xabarda keldi. Saqlamaymiz va
// tarqatmaymiz — yuborgan tab buni qilgan; qayta tarqatsak, tablar
// bir-biriga cheksiz javob qaytaradi (aks-sado)
function boshqaTabdanYangila(xabar) {Tekshiruv. O'tgan darsdagidek: tekshiruv/ skriptlarining chiqishi o'zgarishdan oldin va keyin faylga yoziladi va git diff --no-index bilan solishtiriladi — farq yo'q, hamma qator . Keyin brauzerda tekshiruv/ssenariy.md: qo'shish, belgilash, tahrir, o'chirish, import, ikki tab, ?muvaffaqiyatsiz=1 bilan qaytarish. Hammasi avvalgidek.
Yechim (buyruqlar)
git switch -c refactor/funksiyalar-izohlar
# ... funksiyalarni bo'ling, izohlarni tozalang, tekshiring ...
git add assets/js
git commit -m "refactor: uzun funksiyalar bo'lindi, \
\"nima\" izohlari olib tashlandi, \"nega\" izohlari qo'shildi"
git push -u origin refactor/funksiyalar-izohlar
gh pr create --fill
gh pr merge --mergeNatija: 5 fayl (api.js, asosiy.js, paket.js, render.js, royxat.js), +109 −65. Qatorlar ko'paydi — bu normal: yangi funksiya nomlari va "nega" izohlari joy egallaydi. Maqsad qisqa fayl emas, tez topiladigan va xavfsiz o'zgartiriladigan kod.
E'tibor bering: tekshiruvimiz hozircha qo'lda — skript chiqishini ko'z bilan va diff bilan solishtiramiz. Bu sekin va xato qilish oson. Keyingi darsda uni haqiqiy avtomatik testlarga aylantiramiz.
10. Real ishda
- Kod ko'rib chiqishda eng ko'p yoziladigan izohlar: "bu funksiyani bo'lsa bo'ladimi?", "bu raqam nima?", "izoh koddan farq qilyapti". Kichik funksiyalardan iborat PR tezroq tekshiriladi.
- ESLint qoidalari bir qismini avtomatik ushlaydi:
max-lines-per-function,max-params,max-depth(ichma-ichlik),no-magic-numbers. Ular tavsiya to'plamida yo'q — chegarani jamoa o'zi tanlaydi (ESLint va Prettier darsida sinab ko'ramiz). - Intervyu. "Toza funksiya qanday bo'ladi?", "Qachon izoh yozasiz?", "Guard clause nima?" — ko'pincha kod parchasini ko'rsatib, "buni qanday yaxshilaysiz?" deb so'rashadi.
Xulosa
- Funksiya bitta ish qiladi: ishini "va"siz bir gapda ayta olasiz; ichida bir daraja abstraksiya.
- Ichma-ich shart o'rniga himoya shartlari (erta qaytish): avval xatolar, oxirida asosiy yo'l.
- Parametr 0–2 ta, ko'p bo'lsa — options obyekti; flag argument o'rniga ikki nomli funksiya; so'rov va buyruq alohida.
- Sehrli qiymat o'rniga nomli o'zgarmas (
KUTISH_MS,MAKS_UZUNLIK). - Izoh "nega"ni aytadi; "nima" izohi va izohlangan kod o'chiriladi; eskirgan izoh — yolg'on.
- Formatlash bahsini vosita (Prettier) hal qiladi; fayl gazeta kabi — yuqorida umumiy, pastda tafsilot.
Keyingi dars: Birinchi avtomatik test: node:test va assert — qo'lda solishtirish o'rniga kodni o'zi tekshiradigan testlar yozamiz va vazifalar ning tekshiruv skriptlarini testlarga aylantiramiz.
Manbalar
- Robert C. Martin, "Clean Code", 2008 — 3-bob "Functions", 4-bob "Comments"
- Martin Fowler, "Refactoring", 2-nashr, 2018 — "Extract Function", "Replace Nested Conditional with Guard Clauses", "Remove Flag Argument", "Replace Magic Literal"
- Bertrand Meyer, "Object-Oriented Software Construction" — command-query separation tamoyili
- ESLint qoidalari:
max-lines-per-function,max-params,max-depth,no-magic-numbers— eslint.org/docs/latest/rules
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!