Mundarija (41)
- Bu darsda
- 1. Nega bu kerak?
- 2. Turlar va taqqoslash
- 2.1 typeof null — "object"
- 2.2 == — yashirin o'girish bilan taqqoslash
- 2.3 + satrni yopishtiradi, - esa songa aylantiradi
- 2.4 NaN o'ziga teng emas
- 2.5 || nolni "yo'q" deb biladi
- 3. Sonlar
- 3.1 0.1 + 0.2
- 3.2 map(parseInt)
- 4. Sintaksis: ASI
- 5. Massivlar va mutatsiya
- 5.1 sort() sonlarni satr kabi saralaydi va asl massivni o'zgartiradi
- 5.2 Havola: "nusxa" aslini o'zgartirdi
- 5.3 for...in massivda
- 5.4 Emoji ikki "belgi"
- 6. Funksiyalar va this
- 6.1 Metodni ajratib chaqirish
- 6.2 var va sikldagi closure
- 7. Asinxron tuzoqlar
- 7.1 forEach async callback'ni kutmaydi
- 7.2 Unutilgan await
- 8. 12-qismning o'z tuzoqlari
- 8.1 g flagli regex xotirali
- 8.2 Oy 0 dan boshlanadi
- 8.3 JSON.stringify jimgina tashlab yuboradi
- 9. Hammasi bitta jadvalda
- 10. Tuzoqlarni vositalarga topshiring
- 11. Ko'p uchraydigan xatolar
- 11.1 Tuzoqni "JavaScript'ning xatosi" deb tashlab qo'yish
- 11.2 Belgini davolash, sababni emas
- 11.3 Bitta tuzoqni bilib, qarindoshini unutish
- 12. Mashqlar
- 1-mashq (oson): Natijani ayting
- 2-mashq (o'rta): Uchta tuzoqni toping
- 3-mashq (qiyin): this va forEach ni tuzating
- 4-mashq: Vazifalar qadami — tuzoqlar auditi
- 13. Real ishda
- Xulosa
- Manbalar
JavaScript tuzoqlari: kursda uchragan eng xavfli xatolar bitta ro'yxatda
Qisqacha: JavaScript tuzog'i — kod xato bermaydi, lekin jimgina noto'g'ri natija qaytaradi. Eng xavflilari:
typeof null—"object",==turlarni yashirincha o'zgartiradi,"5" + 2—"52",0.1 + 0.2—0.30000000000000004,[10, 9, 1].sort()—[1, 10, 9],returndan keyin qator tugasa —undefined, metodni ajratib chaqirsangizthisyo'qoladi,forEachesaasynccallback'ni kutmaydi. Davo uchta:===va aniq o'girish (Number(...)), nusxa bilan ishlash (toSorted,structuredClone) va har tuzoqni ushlaydigan vosita — ESLint va test.
Bu darsda
- 08–12-qismlarda uchragan eng xavfli tuzoqlarni bitta xaritada ko'rasiz va har birini qaysi darsda o'rganganingizni eslaysiz.
- Har tuzoqni uch belgisi bilan taniysiz: g'alati natija, xato yo'qligi va "menda ishlayapti".
- Har biri uchun bitta qisqa davo yozasiz.
- Qaysi tuzoqlarni ESLint o'zi ushlashini haqiqiy chiqishda ko'rasiz.
vazifalarkodini tuzoqlar nuqtai nazaridan tekshirasiz.
Oldin bilishingiz kerak: Yashirin coercion qoidalari ichidan, sort va taqqoslash funksiyasi, this yo'qolishi va uni tiklash, Ketma-ket va parallel bajarish, ESLint va Prettier.
1. Nega bu kerak?
«Bahor»ning stajyor dasturchisi Sardor bir haftada uchta xato tuzatdi. Uchalasida ham konsolda qizil yozuv yo'q edi.
Birinchisi: savatdagi "2 ta osh" "21 ta" bo'lib qoldi. Forma maydonidan kelgan "2" satriga 1 qo'shilgan edi. Ikkinchisi: menyuni narx bo'yicha saralasa, ko'k choy (5 000) eng oxiriga tushdi. Uchinchisi: chegirma 0 so'm bo'lsa, tizim baribir 10 foiz chegirma berdi.
Uchala xatoni ham JavaScript "to'g'ri" bajardi. U Sardor yozgan narsani qildi, Sardor o'ylagan narsani emas. Bunday joylar tuzoq deyiladi. Tuzoq — tilning qonuniy, lekin kutilmagan xatti-harakati.
Bu tuzoqlarning hammasini kursda alohida darslarda ko'rgansiz. Lekin ular har xil qismlarda tarqoq yotibdi. Bu dars — ularni bitta "tibbiy ma'lumotnoma"ga yig'adi. Har tuzoq uchun uch narsa: belgisi (qanday ko'rinadi), sababi (nega bunday) va davosi (qanday yozish kerak). Batafsil tushuntirish esa havoladagi darsda turibdi.
Shifokor o'xshatishi: tajribali shifokor kasallikni birinchi belgisidan taniydi. U har safar kitobni boshidan o'qimaydi — belgilar ro'yxati uning boshida. Tajribali dasturchi ham "21" ni ko'rishi bilan "satr qo'shildi" deb o'ylaydi.
flowchart TD
A["Natija g'alati, xato yo'q"] --> B{"Satr va son aralashdimi?"}
B -- "ha" --> C["===, Number(), ??"]
B -- "yo'q" --> D{"Massiv yoki obyekt o'zgardimi?"}
D -- "ha" --> E["toSorted, spread, structuredClone"]
D -- "yo'q" --> F{"Metod boshqa joyda chaqirildimi?"}
F -- "ha" --> G["this: bind yoki arrow"]
F -- "yo'q" --> H{"async bormi?"}
H -- "ha" --> I["for...of + await, Promise.all"]
H -- "yo'q" --> J["Kasr sonmi? Butun so'mda hisoblang"]Bu diagramma — tez tashxis yo'li. Natija g'alati, lekin xato yo'q bo'lsa, savollarni yuqoridan pastga bering. Endi har guruhni alohida ko'ramiz.
2. Turlar va taqqoslash
2.1 typeof null — "object"
console.log(typeof null); // object
console.log(typeof []); // object
console.log(Array.isArray([])); // trueBelgisi: typeof qiymat === "object" tekshiruvidan null ham o'tib ketadi. Keyingi qatorda null.price — TypeError.
Sababi: JavaScript'ning birinchi versiyasidagi xato. Uni tuzatish millionlab saytlarni sindirardi, shuning uchun u abadiy qoldi (typeof va turni to'g'ri aniqlash).
Davosi: obyektni tekshirganda null ni alohida chiqaring: typeof x === "object" && x !== null. Massiv uchun — Array.isArray. vazifalar dagi paket.js aynan shunday tekshiradi.
2.2 == — yashirin o'girish bilan taqqoslash
console.log(0 == ""); // true
console.log("0" == false); // true
console.log(null == undefined); // true
console.log(0 === ""); // falseBelgisi: bo'sh maydon "" "nol" deb hisoblanadi, "0" esa "yolg'on".
Sababi: == turlari har xil bo'lsa, ikkala tomonni bir turga o'tkazadi. Qoidalari uzun va kutilmagan (Tenglik: ==, === va Object.is).
Davosi: har doim ===. Yagona qulay istisno — x == null: u null va undefined ni birga tekshiradi. Lekin jamoada bu istisnoga ruxsat bormi — ESLint sozlamasi hal qiladi.
2.3 + satrni yopishtiradi, - esa songa aylantiradi
const quantity = "2"; // forma maydonidan — har doim satr
console.log(quantity + 1); // 21
console.log(quantity - 1); // 1
console.log(Number(quantity) + 1); // 3
console.log("10" < "9"); // trueBelgisi: Sardorning "21 ta osh" xatosi. Ikkinchi belgi: ikki satr son kabi emas, lug'atdagi kabi taqqoslanadi. "10" < "9", chunki "1" belgisi "9" dan oldin keladi.
Sababi: + operatorida bir tomon satr bo'lsa, ikkinchisi ham satrga aylanadi va ular yopishtiriladi. -, *, / esa faqat sonlar bilan ishlaydi, shuning uchun satrni songa aylantiradi (Yashirin coercion qoidalari ichidan).
Davosi: tashqaridan kelgan qiymatni (forma, URL, dataset, JSON) kirishdayoq aniq o'giring: Number(...) (Turlarni aniq o'zgartirish). vazifalar da Number(nishon.closest("li").dataset.id) — shuning uchun. Usiz "4" === 4 — false bo'lardi va vazifa topilmasdi.
2.4 NaN o'ziga teng emas
console.log(NaN === NaN); // false
console.log(Number.isNaN(Number("osh"))); // true
console.log([NaN].includes(NaN)); // true
console.log([NaN].indexOf(NaN)); // -1Belgisi: if (natija === NaN) hech qachon ishlamaydi.
Sababi: standart shunday deydi: NaN hech narsaga, hatto o'ziga ham teng emas (Number turi JS'da). indexOf === bilan qidiradi, includes esa NaN ni alohida biladi.
Davosi: Number.isNaN(x). Eski global isNaN("osh") ham true beradi — u avval satrni songa aylantiradi, shuning uchun noaniq.
2.5 || nolni "yo'q" deb biladi
const discount = 0; // admin ataylab 0 qo'ydi
console.log(discount || 10); // 10
console.log(discount ?? 10); // 0Belgisi: Sardorning uchinchi xatosi. 0, "" yoki false qiymatlari "standart qiymat" bilan almashib ketadi.
Sababi: || har qanday falsy qiymatda o'ng tomonni oladi (Boolean va truthy/falsy qiymatlar). ?? esa faqat null va undefined da (??, ?. va mantiqiy tayinlash).
Davosi: "qiymat berilmagan bo'lsa" ma'nosida — doim ??.
Tekshirib ko'ring:
const quantity = "3"; console.log(quantity * 2 + 1);nima chiqaradi?
Javob
7. Avval *: u faqat sonlar bilan ishlaydi, "3" — 3 ga aylanadi, 3 * 2 = 6. Keyin 6 + 1 — ikkalasi ham son, yopishtirish yo'q. Agar quantity + 1 bo'lganida — "31" chiqardi.
3. Sonlar
3.1 0.1 + 0.2
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false
console.log((1.005).toFixed(2)); // 1.00
console.log(typeof (1.5).toFixed(2)); // stringBelgisi: chek oxirida 2000.3000000000002 so'm. Yoki 1.005 ni yaxlitlasangiz, 1.01 emas, 1.00 chiqadi.
Sababi: 0.1 ni ikkilik sanoq tizimida aniq yozib bo'lmaydi. Kompyuter unga eng yaqin sonni saqlaydi, 1.005 esa aslida 1.00499999… (Number turi JS'da). Ikkinchi tuzoq: toFixed satr qaytaradi. Unga son qo'shsangiz, yana + bilan yopishtirish boshlanadi.
Davosi: pulni butun sonda hisoblang — so'mda yoki tiyinda (Pul va aniq hisob-kitob). Kasr sonlarni === bilan emas, farq bilan solishtiring: Math.abs(a - b) < Number.EPSILON. Ko'rsatish uchun — Intl.NumberFormat (Intl.NumberFormat).
3.2 map(parseInt)
console.log(["1", "2", "3"].map(parseInt)); // [ 1, NaN, NaN ]
console.log(["1", "2", "3"].map(Number)); // [ 1, 2, 3 ]Belgisi: birinchi element to'g'ri, qolganlari NaN.
Sababi: map callback'ga uchta argument beradi: element, indeks, massiv. parseInt ning ikkinchi parametri — sanoq tizimi. Natijada parseInt("2", 1) chaqiriladi: 1 lik sanoq tizimi yo'q, shuning uchun NaN (Callback imzosi va massivning HOF metodlari).
Davosi: callback'ni aniq yozing: .map((str) => parseInt(str, 10)) yoki shunchaki .map(Number).
4. Sintaksis: ASI
function getDishName() {
return
"Osh";
}
console.log(getDishName()); // undefinedBelgisi: funksiya qiymat qaytarishi kerak edi, lekin undefined qaytardi. Xato yo'q.
Sababi: ASI (Automatic Semicolon Insertion — nuqta-vergulni avtomatik qo'yish). return dan keyin qator tugasa, JavaScript u yerga yashirincha ; qo'yadi. "Osh" esa hech qachon bajarilmaydigan kodga aylanadi (Sintaksis asoslari, return va erta qaytish). Teskari tuzoq ham bor: [ yoki ( bilan boshlanadigan qator oldingi qatorga yopishib ketadi (Massiv destructuring).
Davosi: qaytariladigan qiymat return bilan bitta qatorda boshlansin. Uzun bo'lsa — qavs ochib qo'ying: return ( va keyingi qatorda qiymat. Prettier buni avtomatik shunday formatlaydi.
5. Massivlar va mutatsiya
5.1 sort() sonlarni satr kabi saralaydi va asl massivni o'zgartiradi
const prices = [35000, 5000, 28000];
console.log(prices.sort()); // [ 28000, 35000, 5000 ]
console.log(prices); // [ 28000, 35000, 5000 ]
const menu = [35000, 5000, 28000];
const sorted = menu.toSorted((a, b) => a - b);
console.log(sorted); // [ 5000, 28000, 35000 ]
console.log(menu); // [ 35000, 5000, 28000 ]Belgisi: Sardorning ikkinchi xatosi — ko'k choy oxirida. Ikkinchi belgi: saralagandan keyin asl ro'yxat ham "aralashib" qoldi.
Sababi: taqqoslash funksiyasisiz sort har elementni satrga aylantiradi: "5000" "35000" dan keyin keladi, chunki "5" belgisi "3" dan keyin. Ustiga-ustak, sort massivni joyida o'zgartiradi (sort va taqqoslash funksiyasi).
Davosi: har doim taqqoslash funksiyasi bilan: sonlar — (a, b) => a - b, matn — a.localeCompare(b, "uz"). Asl massiv kerak bo'lsa — toSorted (Nusxa bilan o'zgartirish). vazifalar dagi royxat.js .toSorted(faollarOldin) ishlatadi.
5.2 Havola: "nusxa" aslini o'zgartirdi
const order = { dish: "Osh", extras: ["salat"] };
const copy = { ...order };
copy.dish = "Manti";
copy.extras.push("non");
console.log(order.dish); // Osh
console.log(order.extras); // [ 'salat', 'non' ]Belgisi: bitta mijozning buyurtmasini o'zgartirdingiz — ikkinchisiniki ham o'zgardi.
Sababi: obyekt va massiv o'zgaruvchida havola sifatida saqlanadi (Havola semantikasi). Spread esa sayoz nusxa yasaydi: birinchi qavat yangi, ichidagi massiv — o'sha eski massiv (Sayoz va chuqur nusxalash).
Davosi: ichma-ich ma'lumotni yangilaganda har qavatni nusxalang (Ichma-ich ma'lumotni immutable yangilash) yoki butun nusxa uchun structuredClone(order).
5.3 for...in massivda
const dishes = ["osh", "manti"];
for (const i in dishes) {
console.log(i + 1);
}Konsolda:
01
11Belgisi: "1, 2" kutgan edingiz, 01 va 11 chiqdi.
Sababi: for...in obyekt kalitlarini beradi, kalitlar esa doim satr: "0", "1". Keyin yana + bilan yopishtirish (for...of va for...in).
Davosi: massivda — for...of. Indeks kerak bo'lsa — for (const [i, dish] of dishes.entries()).
5.4 Emoji ikki "belgi"
console.log("👍".length); // 2
console.log([..."👍"].length); // 1Izoh maydoniga "50 belgigacha" chegara qo'ydingiz. Emoji bilan yozgan mehmonga 25 ta emoji ham ko'p bo'lib qoladi. Sababi — length belgilarni emas, UTF-16 bo'laklarini sanaydi (Unicode va emoji). Davosi — [...text].length yoki Intl.Segmenter (Intl.Collator va Intl.Segmenter).
Tekshirib ko'ring:
const a = [3, 20, 100]; const b = a.sort();—avabnima bo'ladi?
Javob
Ikkalasi ham [ 100, 20, 3 ] — va bu bitta massiv. sort satr bo'yicha saraladi ("1" < "2" < "3"), asl massivni o'zgartirdi va o'sha massivni qaytardi. b === a — true.
6. Funksiyalar va this
6.1 Metodni ajratib chaqirish
class Cashier {
name = "Bahor";
getName() {
return this.name;
}
}
const cashier = new Cashier();
const detached = cashier.getName;
console.log(cashier.getName()); // Bahor
try {
detached();
} catch (error) {
console.log(error.message);
}Konsolda:
Bahor
Cannot read properties of undefined (reading 'name')Tarjimasi: "undefined ning xususiyatlarini o'qib bo'lmaydi (name ni o'qishda)".
Belgisi: cashier.getName() ishlaydi, lekin funksiyani o'zgaruvchiga, callback'ga (setTimeout(cashier.getName, 100)) yoki tinglovchiga bersangiz — this yo'qoladi.
Sababi: this funksiya qayerda yozilganiga emas, qanday chaqirilganiga qarab aniqlanadi. detached() da nuqtadan oldin obyekt yo'q — this undefined (this: to'rt qoida, this yo'qolishi va uni tiklash).
Davosi: cashier.getName.bind(cashier) yoki arrow o'ram: () => cashier.getName(). vazifalar dagi api.js da shunga yaqin holat bor: obyekt.fetch(...) ko'rinishida chaqirsangiz, brauzer this ni tekshirib, Illegal invocation xatosini beradi. Shuning uchun u yerda oddiy fetchFn(url, sorov) chaqiruvi va bu haqda izoh turibdi.
6.2 var va sikldagi closure
const tasks = [];
for (var i = 1; i <= 3; i++) {
tasks.push(() => i);
}
console.log(tasks.map((task) => task())); // [ 4, 4, 4 ]Belgisi: uchta funksiya uchta har xil son qaytarishi kerak edi — hammasi 4.
Sababi: var blok scope'ga ega emas: uchala funksiya bitta i ni eslab qoladi. Ular chaqirilganda sikl tugagan, i esa 4 (Closure tuzoqlari).
Davosi: let — har aylanishda yangi i. Natija [ 1, 2, 3 ]. Umuman, var ni yangi kodda ishlatmang (var va nega undan voz kechildi).
Tekshirib ko'ring:
button.addEventListener("click", cashier.getName)— tugma bosilgandathiscashierbo'ladimi?
Javob
Yo'q. Metod ajratib berildi: brauzer uni cashier. siz chaqiradi. Tinglovchi ichida this — tugmaning o'zi bo'ladi. this.name xato ham bermaydi: tugmaning o'z name xususiyati bor (odatda bo'sh satr ""). Natija — "Bahor" o'rniga jim bo'sh satr, ya'ni yana tuzoq. Davosi o'sha: () => cashier.getName() yoki bind(cashier).
7. Asinxron tuzoqlar
7.1 forEach async callback'ni kutmaydi
const wait = (ms) => new Promise((done) => setTimeout(done, ms));
async function prepare(dishes) {
const ready = [];
dishes.forEach(async (dish) => {
await wait(50);
ready.push(dish);
});
console.log("tayyor:", ready.length);
}
await prepare(["osh", "manti"]);Konsolda:
tayyor: 0Belgisi: "hammasi tayyor" xabari ish tugashidan oldin chiqadi. Hisob 0, ro'yxat bo'sh.
Sababi: forEach callback qaytargan Promise'ga qaramaydi. U callback'ni chaqiradi va darhol keyingisiga o'tadi (Ketma-ket va parallel bajarish).
Davosi: ketma-ket kerak bo'lsa — for...of ichida await. Parallel kerak bo'lsa — await Promise.all(dishes.map(async (dish) => …)):
const wait = (ms) => new Promise((done) => setTimeout(done, ms));
async function prepare(dishes) {
const ready = [];
for (const dish of dishes) {
await wait(50);
ready.push(dish);
}
console.log("tayyor:", ready.length);
}
await prepare(["osh", "manti"]); // tayyor: 27.2 Unutilgan await
saqla(royxat) deb yozdingiz, await saqla(royxat) emas. Kod keyingi qatorga o'tib ketadi, xato bo'lsa — hech kim ushlamaydi. Bu suzib yurgan Promise (floating promise) — async / await darsida ko'rgan edik. Belgisi: konsolda Uncaught (in promise) yoki Node'da jarayon qulashi. Davosi: har Promise'ni await qiling, return qiling yoki .catch bering. Ataylab kutmasangiz — izohda nega ekanini yozing.
8. 12-qismning o'z tuzoqlari
8.1 g flagli regex xotirali
const PHONE = /\+998/g;
const notes = ["+998 90", "+998 91", "+998 93"];
console.log(notes.filter((text) => PHONE.test(text)));
// [ '+998 90', '+998 93' ]Belgisi: uchala izohda ham telefon bor, lekin ikkitasi topildi. Bir chaqiruvda true, keyingisida xuddi shu matnga false.
Sababi: g flagli regex lastIndex da qayerda to'xtaganini eslab qoladi. Keyingi test o'sha joydan qidiradi (Flaglar va lastIndex tuzog'i).
Davosi: "bormi?" savoli uchun g qo'ymang. Hamma moslik kerak bo'lsa — match yoki matchAll.
8.2 Oy 0 dan boshlanadi
const booking = new Date(2026, 10, 5); // "5-oktabr" deb yozilgan edi
console.log(booking.toDateString()); // Thu Nov 05 2026Belgisi: bron bir oy keyinga tushdi.
Sababi: new Date(yil, oy, kun) da oy 0 dan sanaladi: 0 — yanvar, 9 — oktabr (Date asoslari). Yana ikki qarindosh tuzoq: "2026-10-05" satri UTC deb o'qiladi, setterlar esa sanani joyida o'zgartiradi (Date va vaqt zonalari).
Davosi: sanani ISO satridan, vaqt va zona bilan yarating: new Date("2026-10-05T12:00:00+05:00"). Yangi loyihalarda — Temporal yoki sinalgan kutubxona (Temporal API va sana kutubxonalari).
8.3 JSON.stringify jimgina tashlab yuboradi
const todo = { text: "Osh", deadline: undefined, score: NaN };
console.log(JSON.stringify(todo)); // {"text":"Osh","score":null}undefined xususiyati yo'qoldi, NaN esa null bo'ldi. Serverga yuborilgan ma'lumot siz o'ylagandek emas (JSON asoslari, JSON chuqur).
Davosi: yuborishdan oldin qiymatni tekshiring (Number.isNaN), "yo'q" qiymat kerak bo'lsa — undefined emas, null yozing: u JSON'da saqlanadi.
Tekshirib ko'ring:
const re = /osh/g; console.log(re.test("osh"), re.test("osh"));nima chiqaradi va nega?
Javob
true false. Birinchi test moslik topdi va lastIndex ni 3 ga surdi. Ikkinchi test 3-o'rindan qidirdi — u yerda hech narsa yo'q, false qaytardi va lastIndex ni 0 ga qaytardi. Davosi: "bormi?" savoli uchun g siz /osh/.
9. Hammasi bitta jadvalda
| Tuzoq | Belgisi | Davosi |
|---|---|---|
typeof null |
null "obyekt" bo'lib o'tadi |
x !== null, Array.isArray |
==, + |
"21", 0 == "" |
===, Number(...) kirishda |
NaN |
=== NaN ishlamaydi |
Number.isNaN |
|| |
0 almashib ketadi |
?? |
0.1 + 0.2 |
…0000004, toFixed satr |
butun so'm, Intl.NumberFormat |
map(parseInt) |
[1, NaN, NaN] |
map(Number) |
| ASI | undefined qaytdi |
return bilan bir qatorda |
sort() |
5000 oxirida, asl o'zgardi |
toSorted((a, b) => a - b) |
| Havola | nusxa aslini o'zgartirdi | spread har qavatda, structuredClone |
this |
undefined ning xususiyati |
bind, arrow o'ram |
forEach + async |
"tayyor" erta chiqdi | for...of, Promise.all |
g + test |
goh true, goh false |
test uchun g siz |
| Oy | bir oy siljidi | ISO satr, Temporal |
Jadvalni eslab qolish shart emas. Muhimi — g'alati natijani ko'rganda "bu tuzoqlardan biri bo'lishi mumkin" deb o'ylash. Keyin shu jadvalga qaytasiz.
10. Tuzoqlarni vositalarga topshiring
Hamma tuzoqni boshda ushlab turish qiyin. Yaxshi xabar: ularning yarmini ESLint siz uchun qidiradi. Quyidagi faylda beshta tuzoq bor. Biz uni vazifalar dagi ESLint 10.12.0 va @eslint/js 10.0.1 bilan, recommended + ikki qo'shimcha qoida (eqeqeq va require-atomic-updates) bilan tekshirdik:
// tuzoq.js
export function getPrice(dish) {
return
dish.price;
}
export function checkType(value) {
if (value == null) return false;
return typeof value === "array";
}
export function check(num) {
return num === NaN;
}
export const tooBig = 9007199254740993;
let stock = 3;
export async function book(wait) {
stock = stock - (await wait());
}npx eslint tuzoq.js ning haqiqiy chiqishi:
4:5 error Unreachable code no-unreachable
8:13 error Expected '===' and instead saw '==' eqeqeq
9:27 error Invalid typeof comparison value valid-typeof
13:10 error Use the isNaN function to compare with NaN use-isnan
16:23 error This number literal will lose precision at runtime no-loss-of-precision
20:3 error Possible race condition: `stock` might be reassigned based on an outdated value of `stock` require-atomic-updates
✖ 6 problems (6 errors, 0 warnings)Qatorma-qator tarjima:
Unreachable code— "yetib bo'lmaydigan kod": ASI tuzog'i,dish.pricehech qachon bajarilmaydi.Expected '===' and instead saw '=='— "===kutilgan edi,==ko'rildi".Invalid typeof comparison value— "typeofbilan noto'g'ri qiymat solishtirilmoqda":typeofhech qachon"array"qaytarmaydi.Use the isNaN function to compare with NaN— "NaNbilan solishtirish uchunisNaNishlating".This number literal will lose precision at runtime— "bu son ishlash paytida aniqligini yo'qotadi":Number.MAX_SAFE_INTEGER(9 007 199 254 740 991) dan katta, oxirgi raqami yo'qoladi (Number turi JS'da).Possible race condition— "poyga holati bo'lishi mumkin":stockeski qiymat asosida qayta yozilmoqda. Bu tuzoqni keyingi darslardan birida — Nozik xatolar da — o'zi takrorlab ko'ramiz.
E'tibor bering: sort(), this, forEach + async va havola tuzoqlarini ESLint'ning standart qoidalari ushlamaydi. Ular uchun — test (Birinchi avtomatik test) va JSDoc bilan tur tekshiruvi (JSDoc va // @ts-check). TypeScript bilan ishlaydigan typescript-eslint qoidalari esa forEach ga async callback berilganini ham ko'rsatadi — buni 15-qismda ko'ramiz.
11. Ko'p uchraydigan xatolar
11.1 Tuzoqni "JavaScript'ning xatosi" deb tashlab qo'yish
"Bu JavaScript'ning g'alati joyi" — va kod o'sha holda qoladi.
G'alati joy — sizning kodingizdagi xato. Til o'zgarmaydi, kodni o'zgartirasiz: aniq o'girish, ===, nusxa.
11.2 Belgini davolash, sababni emas
"21" chiqdi — parseInt(total) bilan "to'g'rilash". 0.30000000000000004 — toFixed(2) bilan yashirish.
Sabab joyida tuzating: satrni maydondan o'qiganda songa aylantiring, pulni boshidan butun so'mda hisoblang.
11.3 Bitta tuzoqni bilib, qarindoshini unutish
sort ga funksiya berdingiz, lekin u hamon asl massivni o'zgartiradi. Shu massivni boshqa joy ham ishlatayotgan bo'lsa (masalan, ekrandagi asl tartib), u ham buziladi. React kabi freymvorklarda (17-qismda) bu holat yangilanmay qolishiga olib keladi.
Har tuzoqning ikki tomoni bor: sort — satr bo'yicha va joyida; Date — oy 0 dan va setter joyida.
12. Mashqlar
1-mashq (oson): Natijani ayting
Har qator nima chiqaradi? Avval o'ylang, keyin yozing.
console.log("7" + 3)→console.log("7" - 3)→console.log(typeof null)→console.log([1, 2, 10].sort().at(-1))→
Yechim
"73" — + da bir tomon satr, yopishtirish. 4 — - songa aylantiradi. "object" — tarixiy xato. 2 — taqqoslash funksiyasisiz satr bo'yicha saralanadi: [ 1, 10, 2 ], chunki "10" "2" dan oldin keladi ("1" < "2"). Oxirgisi — 2.
2-mashq (o'rta): Uchta tuzoqni toping
Funksiya savat jamini hisoblashi kerak. discount — so'mda, 0 bo'lishi mumkin. Kodda uchta tuzoq bor. Ularni toping va tuzating. Ishora: «Turlar va taqqoslash» bo'limidagi forma qiymatlari va ||, «Massivlar va mutatsiya» bo'limidagi sort.
function calculateTotal(cart, discount) {
const prices = cart.map((row) => row.price * row.quantity);
const maxPrice = prices.sort().at(-1);
const total = prices.reduce((sum, n) => sum + n, 0);
return { total: total - (discount || 5000), maxPrice };
}
const cart = [
{ price: 35000, quantity: "2" },
{ price: 5000, quantity: "3" },
];
console.log(calculateTotal(cart, "0"));
// { total: 85000, maxPrice: 70000 }
console.log(calculateTotal(cart, 0));
// { total: 80000, maxPrice: 70000 }Birinchi chaqiruv to'g'ri, ikkinchisi — 5 000 so'm ortiqcha chegirma. Nega?
Yechim
discount || 5000: son0falsy, shuning uchun 5 000 chegirma berildi. Forma maydonidan kelgan"0"esa bo'sh bo'lmagan satr — truthy, shuning uchun birinchi chaqiruv tasodifan to'g'ri ishladi. Davo: kirishdaNumber(discount)va "berilmagan bo'lsa" ma'nosida —undefinedtekshiruvi.row.quantity— satr.35000 * "2"tasodifan ishladi (*songa aylantiradi), lekin kimdir keyin+bilan qo'shsa, buziladi. Davo: kirishdaNumber(row.quantity).prices.sort()— satr bo'yicha va joyida. Bu yerda tasodifan to'g'ri ("15000"<"70000"), lekin[9000, 70000]da 9 000 "eng qimmat" chiqardi. Davo:Math.max(...prices).
function calculateTotal(cart, discount) {
const prices = cart.map(
(row) => row.price * Number(row.quantity),
);
const maxPrice = Math.max(...prices);
const total = prices.reduce((sum, n) => sum + n, 0);
const discountAmount =
discount === undefined ? 5000 : Number(discount);
return { total: total - discountAmount, maxPrice };
}
const cart = [
{ price: 35000, quantity: "2" },
{ price: 5000, quantity: "3" },
];
console.log(calculateTotal(cart, "0"));
// { total: 85000, maxPrice: 70000 }
console.log(calculateTotal(cart, 0));
// { total: 85000, maxPrice: 70000 }
console.log(calculateTotal(cart));
// { total: 80000, maxPrice: 70000 }Nega bu yerda ?? emas? Number(undefined) — NaN, ?? esa NaN ni "yo'q" deb bilmaydi. Shuning uchun avval undefined ni tekshirdik, keyin o'girdik. Tuzoqlarning eng yomon tomoni ham shu mashqda ko'rindi: siz sinagan holatda ("0") kod ishlaydi.
3-mashq (qiyin): this va forEach ni tuzating
Oshxona klassi buyurtmalarni ketma-ket tayyorlaydi. Kod tayyor: 0 chiqaradi va bitta joyda this yo'qoladi. Ikkala tuzoqni tuzating, natija tayyor: 2 bo'lsin. Ishora: «Metodni ajratib chaqirish» va «forEach async callback'ni kutmaydi» bo'limlari.
class Kitchen {
readyDishes = [];
async prepare(dish) {
await new Promise((done) => setTimeout(done, 20));
this.readyDishes.push(dish);
}
async prepareAll(dishes) {
dishes.forEach(this.prepare);
console.log("tayyor:", this.readyDishes.length);
}
}
await new Kitchen().prepareAll(["osh", "manti"]);Yechim
Ikki tuzoq: forEach(this.prepare) metodni ajratib beradi (this — undefined, 20 ms dan keyin TypeError), va forEach Promise'larni kutmaydi.
class Kitchen {
readyDishes = [];
async prepare(dish) {
await new Promise((done) => setTimeout(done, 20));
this.readyDishes.push(dish);
}
async prepareAll(dishes) {
for (const dish of dishes) {
await this.prepare(dish); // nuqta bilan — this joyida
}
console.log("tayyor:", this.readyDishes.length);
}
}
await new Kitchen().prepareAll(["osh", "manti"]);
// tayyor: 2Parallel varianti: await Promise.all(dishes.map((dish) => this.prepare(dish))) — arrow this ni tashqi metoddan oladi.
4-mashq: Vazifalar qadami — tuzoqlar auditi
vazifalar v3.1 kodini o'zgartirmaymiz — uni tekshiramiz. assets/js/ dagi fayllarda quyidagilarni qidiring (VS Code'da Ctrl+Shift+F) va har biriga bir gapli javob yozing: kod bu tuzoqdan qanday qochgan?
sort— qayerda saralanadi va qanday?dataset.id— satrmi yoki sonmi, qayerda o'giriladi?==— bormi?typeof … === "object"—nullhisobga olinganmi?forEach—asynccallback bilanmi?
Javoblarni kurs/mashqlar/12/40-tuzoqlar/audit.md ga yozing.
Yechim
royxat.js:.toSorted(faollarOldin)— nusxa bilan va taqqoslash funksiyasi bilan.faollarOldinmantiqiy qiymatlarni aniq songa aylantiradi:Number(a.bajarildi) - Number(b.bajarildi).datasetqiymati doim satr.asosiy.jsvarender.jsdaNumber(...closest("li").dataset.id)— kirishdayoq songa. Usiztop(id)dagi===hech narsa topmasdi.- Yo'q — hamma joyda
===va!==. Buni #38 dagi ESLintrecommendedta'minlamaydi (eqeqequnda yo'q), bu — kod uslubi. - Ha:
holat.jsvapaket.jsdatypeof qiymat === "object" && qiymat !== null. - Yo'q:
paket.jsvarender.jsdagiforEachcallback'lari sinxron. Asinxron ishlarawaitbilan ketma-ket (sinxronla,serverdaBajar).
git add 12/40-tuzoqlar/audit.md
git commit -m "12/40: vazifalar tuzoqlar auditi"13. Real ishda
- Kod review. Tajribali dasturchilar PR'da aynan shu jadvaldagi joylarni ko'zdan kechiradi: forma qiymati qayerda songa aylanadi?
sortfunksiyasiz emasmi?forEachichidaawaityo'qmi? - Linter sozlamasi. Ko'p jamoalar
eqeqeq,no-implicit-coercion,require-atomic-updateskabi qoidalarnirecommendedga qo'shadi. TypeScript'ga o'tgach,no-floating-promisesvano-misused-promises(typescript-eslint) qo'shiladi — 15-qismda. - Intervyu. "
typeof nullnima?", "[10, 9, 1].sort()nima qaytaradi?", "0.1 + 0.2 === 0.3negafalse?", "thisqachon yo'qoladi?" — boshlang'ich darajadagi JavaScript intervyusining eng ko'p so'raladigan savollari. Javobning o'zi emas, sababi va davosi baholanadi.
Xulosa
- Tuzoq — xato bermaydigan, lekin jimgina noto'g'ri natija: belgisi g'alati qiymat va "menda ishlayapti".
- Turlar:
===, tashqi qiymatni kirishdaNumber(...), standart qiymat uchun??,NaNuchunNumber.isNaN. - Sonlar: pul — butun so'mda;
toFixedsatr qaytaradi;map(parseInt)emas,map(Number). - Massiv va obyekt:
sort— funksiya bilan vatoSorted; spread sayoz;for...inmassivda emas. - Funksiya va asinxron: metodni ajratsangiz
thisyo'qoladi;forEachawaitni kutmaydi;varsikl closure'ida bitta. - ESLint
==, ASI,typeofxatosi,NaNva poyga holatining bir turini ushlaydi; qolganini test ushlaydi.
Keyingi dars: JS versiyalari va brauzer mosligi — yangi imkoniyatni ishlatishdan oldin u qaysi brauzerlarda ishlashini tekshirish, Baseline va polyfill.
Manbalar
- MDN: "Equality comparisons and sameness", "Type coercion",
Array.prototype.sort(),this— developer.mozilla.org - ESLint qoidalari:
eqeqeq,no-unreachable,valid-typeof,use-isnan,no-loss-of-precision,require-atomic-updates— eslint.org/docs/latest/rules - ECMAScript 2026 (ECMA-262, 17-nashr), "Abstract Equality Comparison" (
IsLooselyEqual) — tc39.es/ecma262
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!