JavaScript — 0 dan Expertgacha (O'zbek tilida)¶
📚 README · ← 2-qism — Strukturalar · Keyingi: 4-qism — Asinxron JS →
3-QISM: BRAUZER (DOM) Endi JS'ni HTML sahifa bilan bog'laymiz: matn o'zgartirish, tugma bosish, forma tekshirish, ma'lumot saqlash. Har bir moduldan keyin 20 ta masala (yechimi bilan). Modullar bo'ylab Todo-app quramiz.
1-2 qismda toza JS (mantiq) o'rgandik. Endi shu mantiqni ko'rinadigan natijaga ulaymiz.
9-MODUL: DOM bilan ishlash¶
DOM nima?¶
DOM (Document Object Model) — brauzer sening HTML'ingni o'qib, uni obyektlar daraxti ko'rinishida xotirada saqlaydi. JS shu daraxt orqali sahifani o'qiydi va o'zgartiradi.
Har bir HTML tegi — DOM'da bitta node (tugun). JS shu node'larni topib, ularning matni, rangi, atributlarini o'zgartira oladi. document — butun sahifaning "ildizi".
Element tanlash (Selecting)¶
Avval elementni "ushlab olishing" kerak, keyin u bilan ishlaysan.
// ID bo'yicha (eng tez):
const sarlavha = document.getElementById("sarlavha");
// CSS selektor bo'yicha — BIRINCHI mosini (eng zamonaviy, eng moslashuvchan):
const tugma = document.querySelector(".btn"); // class
const div = document.querySelector("#asosiy"); // id
const birinchiLi = document.querySelector("ul li"); // ichma-ich
// CSS selektor bo'yicha — HAMMA mosini (NodeList qaytaradi):
const hammaLi = document.querySelectorAll("li");
Why
querySelector: U CSS selektorlarining hammasini tushunadi (.class,#id,div > p,[data-id]). Shuning uchun zamonaviy kodda default tanlov —querySelector/querySelectorAll.getElementByIdbiroz tezroq, lekin farqi sezilmaydi.
Matnni o'qish va o'zgartirish¶
const el = document.querySelector("#xabar");
// O'qish:
console.log(el.textContent); // ichidagi matn
// Yozish:
el.textContent = "Yangi matn"; // FAQAT matn (xavfsiz)
el.innerHTML = "<b>Qalin</b> matn"; // HTML sifatida talqin qiladi
Why — XSS xavfsizligi (muhim!):
textContentmatnni shunchaki matn deb yozadi.innerHTMLesa ichidagi HTML teglarini bajaradi. Agar foydalanuvchidan kelgan ma'lumotniinnerHTMLga qo'ysang, u<script>yuborib saytingni buzishi mumkin (XSS hujumi). Qoida: matn uchun doimtextContent,innerHTMLni faqat o'zing ishonchli HTML yozganingda ishlat.
Atributlarni o'zgartirish¶
const rasm = document.querySelector("img");
rasm.src = "yangi.jpg"; // to'g'ridan-to'g'ri
rasm.setAttribute("alt", "Tavsif"); // setAttribute orqali
console.log(rasm.getAttribute("src")); // o'qish
const link = document.querySelector("a");
link.href = "https://example.com";
const input = document.querySelector("input");
console.log(input.value); // input qiymati — .value orqali (textContent emas!)
Class bilan ishlash (classList) — eng muhim¶
Rang/ko'rinishni o'zgartirish uchun inline style emas, class ishlat (CSS'da uslub aniqlangan bo'ladi):
const el = document.querySelector(".karta");
el.classList.add("faol"); // class qo'shadi
el.classList.remove("faol"); // class olib tashlaydi
el.classList.toggle("faol"); // bor bo'lsa oladi, yo'q bo'lsa qo'shadi
el.classList.contains("faol"); // bormi? -> true/false
Why class, style emas:
el.style.color = "red"— uslubni JS'ga aralashtiradi.el.classList.add("xato")— uslub CSS'da qoladi, JS faqat "qaysi holatda" ekanini boshqaradi. Bu — mas'uliyatni ajratish (separation of concerns). Toggle bilan dark mode, active tab kabi narsalar bir qatorda hal bo'ladi.
Style'ni to'g'ridan-to'g'ri o'zgartirish (kamroq)¶
const el = document.querySelector("#quti");
el.style.color = "white";
el.style.backgroundColor = "blue"; // CSS: background-color -> JS: backgroundColor (camelCase)
el.style.display = "none"; // yashirish
Yangi element yaratish va qo'shish¶
Bu — ma'lumotdan ro'yxat yasashning asosi:
// 1. Element yarat
const yangiLi = document.createElement("li");
// 2. Ichini to'ldir
yangiLi.textContent = "Yangi vazifa";
yangiLi.classList.add("vazifa");
// 3. Sahifaga qo'sh
const royxat = document.querySelector("ul");
royxat.appendChild(yangiLi); // oxiriga qo'shadi
// royxat.prepend(yangiLi); // boshiga qo'shadi
Element o'chirish¶
Daraxt bo'ylab harakat (Traversal)¶
const el = document.querySelector(".farzand");
el.parentElement; // ota element
el.children; // bolalari (HTMLCollection)
el.nextElementSibling; // keyingi qo'shni
el.previousElementSibling; // oldingi qo'shni
Massivdan ro'yxat yasash (eng amaliy namuna)¶
const vazifalar = ["O'qish", "Yozish", "Mashq qilish"];
const ul = document.querySelector("#vazifalar");
vazifalar.forEach(vazifa => {
const li = document.createElement("li");
li.textContent = vazifa;
ul.appendChild(li);
});
Why diqqat — performance: Sikl ichida har safar DOM'ga
appendChildqilish — ko'p elementda sekin. Katta ro'yxatdainnerHTMLni bir marta yig'ib qo'yish yokiDocumentFragmentishlatish tezroq. Hozircha kichik ro'yxatlar uchun bu yetarli — lekin bu tushunchani esda tut.
📝 9-modul masalalari (20 ta)¶
Quyidagi HTML asosini ishlating (
.htmlfayl yaratib,<body>ichiga qo'ying):
getElementByIdbilan#sarlavhani tanlab, matnini "Yangilandi" qiling.querySelectorbilan.matnni tanlang va matnini o'qing.querySelectorAllbilan barcha<li>larni oling va sonini chiqaring.#sarlavhaningtextContentini konsolga chiqaring.#qutiichigainnerHTMLbilan<b>Qalin</b>qo'shing.textContentvainnerHTMLfarqini bitta misolda ko'rsating.#qutigaclassList.addbilan"faol"class qo'shing.#qutidaclassList.toggle("faol")ni 2 marta chaqirib natijani kuzating.classList.containsbilan#qutida"faol"borligini tekshiring.#qutining matn ranginistyle.colorbilan qizil qiling.#rasmgasetAttributebilan yangialtbering.#rasmningsrcini "yangi.jpg" ga o'zgartiring.createElement+appendChildbilan#royxatga uchinchi<li>qo'shing.#royxatboshigaprependbilan<li>qo'shing.- Birinchi
<li>niremove()bilan o'chiring. - Birinchi
<li>ningparentElementini topib, uning teg nomini chiqaring. querySelectorAll("li")+forEachbilan har bir<li>ga"element"class qo'shing.#kiritishinput qiymatini (value) konsolga chiqaring.createElementbilan<div>yasab, ichiga<h3>va<p>joylang (card).- Todo qadami:
["O'qish","Yozish","Kodlash"]massividan#royxatichida<li>lar yasab chiqaring (render funksiyasi).
► Yechimlar
// 1
document.getElementById("sarlavha").textContent = "Yangilandi";
// 2
console.log(document.querySelector(".matn").textContent);
// 3
console.log(document.querySelectorAll("li").length); // 2
// 4
console.log(document.querySelector("#sarlavha").textContent);
// 5
document.querySelector("#quti").innerHTML = "<b>Qalin</b>";
// 6
const q = document.querySelector("#quti");
q.textContent = "<b>matn</b>"; // ekranda <b>matn</b> ko'rinadi (teg bajarilmaydi)
q.innerHTML = "<b>matn</b>"; // ekranda matn QALIN bo'lib chiqadi
// 7
document.querySelector("#quti").classList.add("faol");
// 8 -> 1-chaqiriq qo'shadi, 2-chaqiriq oladi (natija: yo'q)
const qu = document.querySelector("#quti");
qu.classList.toggle("faol"); // qo'shildi
qu.classList.toggle("faol"); // olindi
// 9
console.log(document.querySelector("#quti").classList.contains("faol"));
// 10
document.querySelector("#quti").style.color = "red";
// 11
document.querySelector("#rasm").setAttribute("alt", "Yangi tavsif");
// 12
document.querySelector("#rasm").src = "yangi.jpg";
// 13
const li13 = document.createElement("li");
li13.textContent = "Uch";
document.querySelector("#royxat").appendChild(li13);
// 14
const li14 = document.createElement("li");
li14.textContent = "Nol";
document.querySelector("#royxat").prepend(li14);
// 15
document.querySelector("#royxat li").remove();
// 16 -> "UL"
console.log(document.querySelector("#royxat li").parentElement.tagName);
// 17
document.querySelectorAll("li").forEach(li => li.classList.add("element"));
// 18
console.log(document.querySelector("#kiritish").value);
// 19
const card = document.createElement("div");
const h3 = document.createElement("h3");
h3.textContent = "Sarlavha";
const p = document.createElement("p");
p.textContent = "Tavsif matni";
card.appendChild(h3);
card.appendChild(p);
document.body.appendChild(card);
// 20 — render funksiyasi
function render(vazifalar) {
const ul = document.querySelector("#royxat");
ul.innerHTML = ""; // avval tozalaymiz
vazifalar.forEach(v => {
const li = document.createElement("li");
li.textContent = v;
ul.appendChild(li);
});
}
render(["O'qish", "Yozish", "Kodlash"]);
10-MODUL: Events (hodisalar)¶
Event nima?¶
Event — sahifada sodir bo'ladigan hodisa: tugma bosildi, matn yozildi, sichqoncha harakatlandi, forma yuborildi. JS shu hodisalarni "tinglab", javob beradi.
addEventListener — hodisani tinglash¶
const tugma = document.querySelector("#tugma");
tugma.addEventListener("click", function() {
console.log("Tugma bosildi!");
});
// Arrow bilan (zamonaviy):
tugma.addEventListener("click", () => {
alert("Salom!");
});
Sintaksis: element.addEventListener("hodisa_nomi", funksiya). Bosilganda funksiya ishlaydi.
Why
addEventListener,onclickemas: HTML'da<button onclick="...">yozma.addEventListenerning afzalligi: bitta elementga bir nechta listener ulay olasan, HTML'ni JS'dan ajratasan, varemoveEventListenerbilan o'chira olasan. Bu — toza yondashuv.
Ko'p ishlatiladigan hodisalar¶
el.addEventListener("click", fn); // bosish
el.addEventListener("dblclick", fn); // ikki marta bosish
el.addEventListener("input", fn); // matn yozilganda (har harfda)
el.addEventListener("change", fn); // qiymat o'zgarib, fokus ketganda
el.addEventListener("submit", fn); // forma yuborilganda
el.addEventListener("keydown", fn); // klavisha bosilganda
el.addEventListener("keyup", fn); // klavisha qo'yib yuborilganda
el.addEventListener("mouseover", fn); // sichqoncha ustiga kelganda
el.addEventListener("mouseout", fn); // sichqoncha chiqib ketganda
el.addEventListener("focus", fn); // input fokus olganda
el.addEventListener("blur", fn); // input fokus yo'qotganda
Event obyekti (e)¶
Listener funksiyasiga brauzer hodisa haqida ma'lumot beradi — buni odatda e yoki event deb nomlaymiz:
const input = document.querySelector("#kiritish");
input.addEventListener("input", (e) => {
console.log(e.target); // hodisa sodir bo'lgan element
console.log(e.target.value); // input ichidagi matn (har yozilganda)
});
document.addEventListener("keydown", (e) => {
console.log(e.key); // bosilgan klavisha (masalan "Enter", "a", "ArrowUp")
});
e ning eng muhim qismlari:
- e.target — hodisa sodir bo'lgan element.
- e.target.value — input/textarea/select qiymati.
- e.key — bosilgan klavisha (klaviatura hodisalarida).
- e.preventDefault() — brauzerning standart xatti-harakatini to'xtatadi.
preventDefault() — standart harakatni to'xtatish¶
const link = document.querySelector("a");
link.addEventListener("click", (e) => {
e.preventDefault(); // link sahifaga o'tmaydi
console.log("Bosildi, lekin o'tmadik");
});
// Eng ko'p ishlatiladigan joy — forma (sahifa qayta yuklanmasligi uchun):
form.addEventListener("submit", (e) => {
e.preventDefault(); // sahifa yangilanmaydi
// o'z mantiqing...
});
Why: Forma yuborilganda brauzer odatda sahifani qayta yuklaydi (eski usul). SPA (Vue/React) va AJAX'da bu kerak emas —
e.preventDefault()shu standart yuklanishni to'xtatadi, sen o'zing JS bilan ish ko'rasan.
Hisoblagich misoli (DOM + Event birga)¶
<p id="son">0</p>
<button id="qosh">+1</button>
<script>
let hisob = 0;
const sonEl = document.querySelector("#son");
document.querySelector("#qosh").addEventListener("click", () => {
hisob++;
sonEl.textContent = hisob; // ekranni yangilaymiz
});
</script>
Event Delegation (muhim pattern)¶
Ko'p elementga alohida listener ulash o'rniga, ota elementga bitta listener ulab, e.target orqali qaysi bola bosilganini aniqlaysan:
const royxat = document.querySelector("#royxat");
royxat.addEventListener("click", (e) => {
if (e.target.tagName === "LI") {
e.target.classList.toggle("bajarildi");
}
});
Why delegation: Bu — eng kuchli pattern. Sabablari: (1) keyin dinamik qo'shilgan elementlar ham avtomatik ishlaydi (yangi
<li>ga alohida listener kerak emas); (2) 100 ta listener o'rniga bitta — tez va kam xotira. Todo-app, jadval, ro'yxat — hammasida shuni ishlat.Delegation aynan shu sababli ishlaydi: bola element bosilganda hodisa undan ota elementlar sari tepaga ko'tariladi (bubbling). Aslida har hodisa uch fazadan o'tadi — avval tepadan tushadi (capturing), maqsadga yetadi (target), so'ng yana tepaga ko'tariladi (bubbling):
Bir nechta elementga listener (forEach)¶
const tugmalar = document.querySelectorAll(".tugma");
tugmalar.forEach(tugma => {
tugma.addEventListener("click", () => {
console.log("Bosildi:", tugma.textContent);
});
});
data-* atributlari (dataset)¶
Elementga maxsus ma'lumot biriktirish uchun:
tugma.addEventListener("click", (e) => {
console.log(e.target.dataset.id); // "42"
console.log(e.target.dataset.amal); // "ochir"
});
Why
data-*: Element bilan birga "qaysi yozuvga tegishli" degan ma'lumotni saqlaydi. Todo-app'da har<li>gadata-idqo'yib, o'chirishda qaysi vazifani o'chirishni bilasan.
📝 10-modul masalalari (20 ta)¶
HTML asosi:
<h1 id="natija">Natija</h1> <button id="btn">Bosing</button> <input id="kiritish" type="text"> <select id="tanlov"><option>Bir</option><option>Ikki</option></select> <input type="checkbox" id="belgi"> <ul id="royxat"><li data-id="1">A</li><li data-id="2">B</li></ul> <div class="tugmalar"><button>X</button><button>Y</button></div>
#btnbosilganda konsolga "Bosildi" chiqaring.#btnbosilganda#natijamatnini "Tugma bosildi" qiling.- Hisoblagich:
#btnhar bosilganda#natijada son 1 ga oshsin. #kiritishga yozilganda (input) yozilgan matn#natijada jonli ko'rinsin.e.target.valueniinputhodisasida olib chiqaring.keydown: bosilgan klavishani (e.key)#natijada ko'rsating.#kiritishda Enter bosilganda "Yuborildi" chiqaring.#tanlov(change) o'zgarganda tanlangan qiymatni chiqaring.#belgicheckbox holatini (checked) bosilganda chiqaring.#btngamouseover/mouseoutda rangini o'zgartiring.#btnbosilganda#natijanidisplay:none/blockbilan yashiring/ko'rsating (toggle).- Linkka
preventDefaultqo'llab, bosilganda o'tmasligini ta'minlang. dblclick:#natijaikki marta bosilganda matnini tozalang.- Event delegation:
#royxatga listener qo'yib, bosilgan<li>ga"faol"class qo'shing. .tugmalarichidagi har bir tugmagaforEachbilan listener qo'shing (matnini chiqarsin).#royxat<li>bosilgandae.target.dataset.idni chiqaring.removeEventListenerbilan listener'ni bir martadan keyin o'chiring.#kiritishfocus/blurda border rangini o'zgartiring (classList).keydownbilan ArrowUp/ArrowDown bosilganda son oshsin/kamaysin.- Todo qadami:
#kiritishga vazifa yozib#btnbosilganda, vazifani massivga qo'shib#royxatni qayta render qiling.
► Yechimlar
// 1
document.querySelector("#btn").addEventListener("click", () => console.log("Bosildi"));
// 2
document.querySelector("#btn").addEventListener("click", () => {
document.querySelector("#natija").textContent = "Tugma bosildi";
});
// 3
let hisob = 0;
document.querySelector("#btn").addEventListener("click", () => {
hisob++;
document.querySelector("#natija").textContent = hisob;
});
// 4
document.querySelector("#kiritish").addEventListener("input", (e) => {
document.querySelector("#natija").textContent = e.target.value;
});
// 5
document.querySelector("#kiritish").addEventListener("input", (e) => {
console.log(e.target.value);
});
// 6
document.addEventListener("keydown", (e) => {
document.querySelector("#natija").textContent = e.key;
});
// 7
document.querySelector("#kiritish").addEventListener("keydown", (e) => {
if (e.key === "Enter") console.log("Yuborildi");
});
// 8
document.querySelector("#tanlov").addEventListener("change", (e) => {
console.log(e.target.value);
});
// 9
document.querySelector("#belgi").addEventListener("change", (e) => {
console.log(e.target.checked); // true/false
});
// 10
const btn = document.querySelector("#btn");
btn.addEventListener("mouseover", () => btn.style.backgroundColor = "blue");
btn.addEventListener("mouseout", () => btn.style.backgroundColor = "");
// 11
document.querySelector("#btn").addEventListener("click", () => {
const n = document.querySelector("#natija");
n.style.display = n.style.display === "none" ? "block" : "none";
});
// 12
document.querySelector("a")?.addEventListener("click", (e) => {
e.preventDefault();
console.log("O'tmadik");
});
// 13
document.querySelector("#natija").addEventListener("dblclick", (e) => {
e.target.textContent = "";
});
// 14 — event delegation
document.querySelector("#royxat").addEventListener("click", (e) => {
if (e.target.tagName === "LI") e.target.classList.toggle("faol");
});
// 15
document.querySelectorAll(".tugmalar button").forEach(b => {
b.addEventListener("click", () => console.log(b.textContent));
});
// 16
document.querySelector("#royxat").addEventListener("click", (e) => {
if (e.target.tagName === "LI") console.log(e.target.dataset.id);
});
// 17
function birMarta() {
console.log("Faqat bir marta");
document.querySelector("#btn").removeEventListener("click", birMarta);
}
document.querySelector("#btn").addEventListener("click", birMarta);
// (yoki: addEventListener("click", fn, { once: true }))
// 18
const inp = document.querySelector("#kiritish");
inp.addEventListener("focus", () => inp.classList.add("faol"));
inp.addEventListener("blur", () => inp.classList.remove("faol"));
// 19
let qiymat = 0;
document.addEventListener("keydown", (e) => {
if (e.key === "ArrowUp") qiymat++;
if (e.key === "ArrowDown") qiymat--;
document.querySelector("#natija").textContent = qiymat;
});
// 20 — Todo qo'shish
const vazifalar = [];
function render() {
const ul = document.querySelector("#royxat");
ul.innerHTML = "";
vazifalar.forEach(v => {
const li = document.createElement("li");
li.textContent = v;
ul.appendChild(li);
});
}
document.querySelector("#btn").addEventListener("click", () => {
const input = document.querySelector("#kiritish");
if (input.value.trim() !== "") {
vazifalar.push(input.value.trim());
input.value = "";
render();
}
});
11-MODUL: Forms va validation¶
Forma — foydalanuvchidan ma'lumot olishning asosiy yo'li. JS bilan uni tekshiramiz (validation) va qayta ishlaymiz.
Forma qiymatlarini olish¶
<form id="forma">
<input id="ism" type="text">
<input id="parol" type="password">
<input id="rozilik" type="checkbox">
<select id="shahar">
<option value="tsh">Toshkent</option>
<option value="smq">Samarqand</option>
</select>
<button type="submit">Yuborish</button>
</form>
const ism = document.querySelector("#ism").value; // matn
const parol = document.querySelector("#parol").value;
const rozimi = document.querySelector("#rozilik").checked; // true/false
const shahar = document.querySelector("#shahar").value; // "tsh" yoki "smq"
Eslab qol: Matn maydonlari uchun
.value, checkbox/radio uchun.checked.
submit hodisasi + preventDefault¶
const forma = document.querySelector("#forma");
forma.addEventListener("submit", (e) => {
e.preventDefault(); // sahifa qayta yuklanmaydi
const ism = document.querySelector("#ism").value;
console.log("Yuborildi:", ism);
});
Why submit, click emas: Listener'ni tugmaga emas, formaga
submitga ulash kerak. Sababi: foydalanuvchi Enter bosib ham forma yuborishi mumkin —submitikkalasini ham ushlaydi.e.preventDefault()siz sahifa yangilanib, hamma ma'lumot yo'qoladi.
Oddiy validatsiya¶
forma.addEventListener("submit", (e) => {
e.preventDefault();
const ism = document.querySelector("#ism").value.trim();
const parol = document.querySelector("#parol").value;
// Bo'sh tekshiruv:
if (ism === "") {
console.log("Ism kiritilmagan");
return; // davom etmaymiz
}
// Uzunlik tekshiruvi:
if (parol.length < 6) {
console.log("Parol kamida 6 ta belgi bo'lsin");
return;
}
console.log("Hammasi to'g'ri!");
});
Email tekshiruvi¶
const email = document.querySelector("#email").value;
// Oddiy (includes bilan):
if (!email.includes("@") || !email.includes(".")) {
console.log("Email noto'g'ri");
}
// Aniqroq (regex bilan — 23-modulda chuqur ko'ramiz):
const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!pattern.test(email)) {
console.log("Email formati xato");
}
Xato xabarini ekranda ko'rsatish¶
Konsol emas, foydalanuvchiga ko'rinadigan xabar:
const ismXato = document.querySelector("#ismXato");
if (ism === "") {
ismXato.textContent = "Ism majburiy";
document.querySelector("#ism").classList.add("xato-border");
} else {
ismXato.textContent = "";
document.querySelector("#ism").classList.remove("xato-border");
}
Real-time validatsiya (input hodisasida)¶
Foydalanuvchi yozar ekan tekshirish (UX yaxshilanadi):
const parol = document.querySelector("#parol");
const xabar = document.querySelector("#parolXato");
parol.addEventListener("input", () => {
if (parol.value.length < 6) {
xabar.textContent = "Yana " + (6 - parol.value.length) + " ta belgi kerak";
} else {
xabar.textContent = "✓ Yaxshi";
}
});
FormData (barcha qiymatlarni bir vaqtda)¶
Ko'p maydonli formada qulay:
forma.addEventListener("submit", (e) => {
e.preventDefault();
const data = new FormData(forma);
console.log(data.get("ism")); // name="ism" maydonidan
// Obyektga aylantirish:
const obyekt = Object.fromEntries(data);
console.log(obyekt); // { ism: "...", parol: "..." }
});
Eslatma:
FormDataishlashi uchun input'lardanameatributi bo'lishi kerak (<input name="ism">).
📝 11-modul masalalari (20 ta)¶
HTML asosi:
<form id="forma"> <input id="ism" name="ism" type="text"> <input id="email" name="email" type="email"> <input id="parol" name="parol" type="password"> <input id="tasdiq" name="tasdiq" type="password"> <input id="yosh" name="yosh" type="number"> <input id="rozilik" type="checkbox"> <select id="shahar"><option value="tsh">Toshkent</option></select> <span id="xato" class="xato"></span> <button type="submit">Yuborish</button> </form>
- Formaga
submitlistener qo'shib,preventDefaultqiling. #ismqiymatini submitda olib chiqaring.#ismbo'sh bo'lsa "Ism majburiy" deb#xatoda ko'rsating.#parol6 belgidan qisqa bo'lsa xato bering.#emailda@yo'q bo'lsa xato bering.- Email'ni regex bilan tekshiring (
test). #rozilikbelgilanmagan bo'lsa "Shartlarga rozi bo'ling" deng.#shahartanlangan qiymatini chiqaring.#yosh0 dan kichik yoki bo'sh bo'lsa xato bering.#parolva#tasdiqmos kelmasa "Parollar mos emas" deng.- Xato bo'lsa input'ga
"xato-border"class qo'shing, to'g'ri bo'lsa oling. - Hamma to'g'ri bo'lsa "Muvaffaqiyatli!" deb ko'rsatib, formani tozalang (
reset). FormDatabilan barcha qiymatlarni obyekt qilib oling.#parolga real-time (input) validatsiya qo'shing.- Submit tugmasini
#rozilikbelgilanmagunchadisabledqiling. #yoshfaqat son ekanini tekshiring (isNaN).#ismkamida 3 ta belgi bo'lsin (trim'dan keyin).- Telefon
"+998"bilan boshlanishini tekshiring (startsWith). - Barcha xatolarni bir vaqtda yig'ib, ro'yxat qilib ko'rsating (massiv).
- To'liq forma: ism(≥3), email(regex), parol(≥6), tasdiq(mos) — hammasini tekshirib, faqat to'liq to'g'ri bo'lsa "Ro'yxatdan o'tdingiz" deng.
► Yechimlar
const forma = document.querySelector("#forma");
const xato = document.querySelector("#xato");
// 1
forma.addEventListener("submit", (e) => e.preventDefault());
// 2
forma.addEventListener("submit", (e) => {
e.preventDefault();
console.log(document.querySelector("#ism").value);
});
// 3
function tekshir3() {
const ism = document.querySelector("#ism").value.trim();
if (ism === "") { xato.textContent = "Ism majburiy"; return false; }
return true;
}
// 4
const parol = document.querySelector("#parol");
if (parol.value.length < 6) xato.textContent = "Parol ≥ 6 belgi";
// 5
const email = document.querySelector("#email");
if (!email.value.includes("@")) xato.textContent = "Email noto'g'ri";
// 6
const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!pattern.test(email.value)) xato.textContent = "Email formati xato";
// 7
if (!document.querySelector("#rozilik").checked)
xato.textContent = "Shartlarga rozi bo'ling";
// 8
console.log(document.querySelector("#shahar").value);
// 9
const yosh = document.querySelector("#yosh").value;
if (yosh === "" || Number(yosh) <= 0) xato.textContent = "Yosh noto'g'ri";
// 10
const tasdiq = document.querySelector("#tasdiq").value;
if (parol.value !== tasdiq) xato.textContent = "Parollar mos emas";
// 11
function belgi(el, xatomi) {
if (xatomi) el.classList.add("xato-border");
else el.classList.remove("xato-border");
}
// 12
function muvaffaqiyat() {
xato.textContent = "Muvaffaqiyatli!";
forma.reset();
}
// 13
forma.addEventListener("submit", (e) => {
e.preventDefault();
const data = Object.fromEntries(new FormData(forma));
console.log(data); // { ism, email, parol, tasdiq, yosh }
});
// 14
parol.addEventListener("input", () => {
xato.textContent = parol.value.length < 6
? `Yana ${6 - parol.value.length} ta belgi`
: "✓ Yaxshi";
});
// 15
const rozilik = document.querySelector("#rozilik");
const btn = forma.querySelector("button");
rozilik.addEventListener("change", () => {
btn.disabled = !rozilik.checked;
});
// 16
if (isNaN(Number(yosh)) || yosh === "") xato.textContent = "Faqat son";
// 17
if (document.querySelector("#ism").value.trim().length < 3)
xato.textContent = "Ism ≥ 3 belgi";
// 18 (telefon maydonini #ism deb faraz qildik)
const tel = "+998901234567";
if (!tel.startsWith("+998")) xato.textContent = "+998 bilan boshlansin";
// 19 — barcha xatolarni yig'ish
function hammaXatolar() {
const xatolar = [];
const ism = document.querySelector("#ism").value.trim();
if (ism.length < 3) xatolar.push("Ism ≥ 3 belgi");
if (!pattern.test(email.value)) xatolar.push("Email noto'g'ri");
if (parol.value.length < 6) xatolar.push("Parol ≥ 6 belgi");
return xatolar;
}
// 20 — to'liq forma
forma.addEventListener("submit", (e) => {
e.preventDefault();
const xatolar = [];
const ism = document.querySelector("#ism").value.trim();
const em = document.querySelector("#email").value;
const pa = document.querySelector("#parol").value;
const ta = document.querySelector("#tasdiq").value;
if (ism.length < 3) xatolar.push("Ism kamida 3 ta belgi");
if (!pattern.test(em)) xatolar.push("Email formati noto'g'ri");
if (pa.length < 6) xatolar.push("Parol kamida 6 ta belgi");
if (pa !== ta) xatolar.push("Parollar mos kelmadi");
if (xatolar.length > 0) {
xato.innerHTML = xatolar.map(x => `• ${x}`).join("<br>");
} else {
xato.textContent = "Ro'yxatdan o'tdingiz ✓";
forma.reset();
}
});
12-MODUL: localStorage (ma'lumot saqlash)¶
Web Storage nima?¶
localStorage — brauzerda ma'lumot saqlash imkoniyati. Sahifa yangilangandan keyin ham, hatto brauzer yopilib qayta ochilsa ham ma'lumot saqlanib qoladi. Hisoblagich, theme tanlovi, savatcha — shu yerda saqlanadi.
// Saqlash:
localStorage.setItem("ism", "Oqil");
// O'qish:
const ism = localStorage.getItem("ism"); // "Oqil"
// O'chirish:
localStorage.removeItem("ism");
// Hammasini tozalash:
localStorage.clear();
localStorage vs sessionStorage¶
localStorage.setItem("a", "1"); // brauzer yopilsa ham QOLADI
sessionStorage.setItem("b", "2"); // tab/oyna yopilsa O'CHADI
| localStorage | sessionStorage | |
|---|---|---|
| Yashash muddati | Doimiy (qo'lda o'chirilguncha) | Tab yopilguncha |
| Hajmi | ~5-10 MB | ~5-10 MB |
| Ishlatilishi | Theme, til, savatcha | Vaqtinchalik holat |
⚠️ Faqat matn saqlaydi!¶
localStorage faqat string saqlaydi. Son saqlasang ham, qaytib string bo'lib chiqadi:
localStorage.setItem("yosh", 25);
const yosh = localStorage.getItem("yosh");
console.log(yosh); // "25" (string!)
console.log(typeof yosh); // "string"
console.log(Number(yosh) + 1); // 26 — qayta songa aylantirish kerak
Obyekt/massiv saqlash (JSON bilan)¶
Obyekt yoki massivni saqlash uchun avval matnga aylantirasan (7-modulda ko'rgan JSON):
const user = { ism: "Oqil", yosh: 25 };
// Saqlash: obyekt -> JSON matn
localStorage.setItem("user", JSON.stringify(user));
// O'qish: JSON matn -> obyekt
const saqlangan = JSON.parse(localStorage.getItem("user"));
console.log(saqlangan.ism); // "Oqil"
// Massiv ham xuddi shunday:
const vazifalar = ["O'qish", "Yozish"];
localStorage.setItem("vazifalar", JSON.stringify(vazifalar));
const olingan = JSON.parse(localStorage.getItem("vazifalar"));
Why diqqat:
localStorage.setItem("user", user)deb to'g'ridan-to'g'ri obyekt bersang, u"[object Object]"bo'lib saqlanadi (buzilgan). Obyekt/massiv uchun doimJSON.stringify/JSON.parseishlat.
Mavjudligini tekshirish¶
getItem topa olmasa null qaytaradi:
const ism = localStorage.getItem("ism");
if (ism === null) {
console.log("Hali saqlanmagan");
} else {
console.log("Salom, " + ism);
}
// Yoki qisqa (default bilan):
const til = localStorage.getItem("til") || "uz";
Amaliy: Dark mode (theme) saqlash¶
<button id="theme">Theme almashtirish</button>
<script>
// Sahifa yuklanganda saqlangan theme'ni qo'llash:
const saqlangan = localStorage.getItem("theme");
if (saqlangan === "dark") {
document.body.classList.add("dark");
}
document.querySelector("#theme").addEventListener("click", () => {
document.body.classList.toggle("dark");
// Holatni saqlash:
const hozir = document.body.classList.contains("dark") ? "dark" : "light";
localStorage.setItem("theme", hozir);
});
</script>
Why — xavfsizlik eslatmasi:
localStoragega maxfiy ma'lumot saqlama (parol, JWT token, bank ma'lumotlari). Sababi: u oddiy matn ko'rinishida turadi va har qanday JS (jumladan XSS orqali kirgan zararli kod) uni o'qiy oladi. Faqat zararsiz, foydalanuvchi qulayligi uchun ma'lumotlarni saqla (theme, til, UI holati).
📝 12-modul masalalari (20 ta)¶
localStorage.setItembilan"ism"ga o'z isimingni saqlang.getItembilan uni o'qib, konsolga chiqaring.removeItembilan"ism"ni o'chiring.clear()bilan hammasini tozalang."ism"saqlanmagan bo'lsa (null) "Mehmon" deb chiqaring.- Son
100ni saqlang, o'qing, songa aylantirib+50qiling. {ism:"Oqil", yosh:25}obyektiniJSON.stringifybilan saqlang.- Uni
JSON.parsebilan qaytarib o'qing va.ismni chiqaring. ["a","b","c"]massivini saqlang va o'qing.- Hisoblagich: tugma bosilganda son oshib,
localStorageda saqlansin (sahifa yangilansa ham qolsin). - Theme toggle: dark/light holatini saqlang.
- Sahifa yuklanganda saqlangan theme'ni
bodyga qo'llang. - Ism saqlang; keyingi tashrifda "Yana xush kelibsiz, X" deng.
- Saqlangan massivga yangi element qo'shib, qayta saqlang.
- Saqlangan massivdan element o'chirib, qayta saqlang.
"til"saqlanmagan bo'lsa default"uz"ni ishlating (|| "uz").sessionStoragega ma'lumot saqlab,localStoragedan farqini tushuntiring.- Oxirgi tashrif vaqtini (
new Date().toISOString()) saqlang va ko'rsating. localStorageda nechta kalit borligini (localStorage.length) chiqaring.- TO'LIQ TODO-APP: input + tugma + ro'yxat. Vazifa qo'shish, o'chirish (delegation), va
localStorageda saqlash (sahifa yangilansa ham qolsin).
► Yechimlar
// 1
localStorage.setItem("ism", "Oqil");
// 2
console.log(localStorage.getItem("ism")); // "Oqil"
// 3
localStorage.removeItem("ism");
// 4
localStorage.clear();
// 5
console.log(localStorage.getItem("ism") ?? "Mehmon");
// 6 -> 150
localStorage.setItem("son", 100);
console.log(Number(localStorage.getItem("son")) + 50);
// 7
localStorage.setItem("user", JSON.stringify({ ism: "Oqil", yosh: 25 }));
// 8 -> "Oqil"
console.log(JSON.parse(localStorage.getItem("user")).ism);
// 9
localStorage.setItem("harflar", JSON.stringify(["a", "b", "c"]));
console.log(JSON.parse(localStorage.getItem("harflar")));
// 10 — saqlanadigan hisoblagich
let hisob = Number(localStorage.getItem("hisob")) || 0;
document.querySelector("#btn")?.addEventListener("click", () => {
hisob++;
localStorage.setItem("hisob", hisob);
document.querySelector("#natija").textContent = hisob;
});
// 11 & 12 — theme
if (localStorage.getItem("theme") === "dark") document.body.classList.add("dark");
document.querySelector("#theme")?.addEventListener("click", () => {
document.body.classList.toggle("dark");
localStorage.setItem("theme", document.body.classList.contains("dark") ? "dark" : "light");
});
// 13
const eski = localStorage.getItem("ism");
if (eski) console.log(`Yana xush kelibsiz, ${eski}`);
localStorage.setItem("ism", "Oqil");
// 14
const arr14 = JSON.parse(localStorage.getItem("harflar")) || [];
arr14.push("d");
localStorage.setItem("harflar", JSON.stringify(arr14));
// 15
let arr15 = JSON.parse(localStorage.getItem("harflar")) || [];
arr15 = arr15.filter(x => x !== "b"); // "b" ni o'chir
localStorage.setItem("harflar", JSON.stringify(arr15));
// 16
const til = localStorage.getItem("til") || "uz";
console.log(til);
// 17
sessionStorage.setItem("vaqtinchalik", "123");
// Farqi: tab yopilsa o'chadi; localStorage qoladi.
// 18
localStorage.setItem("oxirgiTashrif", new Date().toISOString());
console.log(localStorage.getItem("oxirgiTashrif"));
// 19
console.log(localStorage.length);
// 20 — TO'LIQ TODO-APP (alohida pastda)
20-masala: To'liq Todo-app (HTML + JS)¶
<!DOCTYPE html>
<html lang="uz">
<head>
<meta charset="UTF-8">
<title>Todo App</title>
<style>
body { font-family: sans-serif; max-width: 400px; margin: 40px auto; }
li { cursor: pointer; padding: 6px; list-style: none; }
li.bajarildi { text-decoration: line-through; color: gray; }
.ochir { color: red; margin-left: 10px; }
</style>
</head>
<body>
<h1>Vazifalar</h1>
<input id="kiritish" type="text" placeholder="Yangi vazifa...">
<button id="qosh">Qo'shish</button>
<ul id="royxat"></ul>
<script>
// localStorage'dan yuklab olamiz (bo'lmasa bo'sh massiv)
let vazifalar = JSON.parse(localStorage.getItem("vazifalar")) || [];
const ul = document.querySelector("#royxat");
const input = document.querySelector("#kiritish");
// Saqlash funksiyasi
function saqla() {
localStorage.setItem("vazifalar", JSON.stringify(vazifalar));
}
// Render funksiyasi
function render() {
ul.innerHTML = "";
vazifalar.forEach((v, index) => {
const li = document.createElement("li");
li.textContent = v.matn;
if (v.bajarildi) li.classList.add("bajarildi");
li.dataset.index = index;
const ochir = document.createElement("span");
ochir.textContent = "✕";
ochir.className = "ochir";
ochir.dataset.ochir = index;
li.appendChild(ochir);
ul.appendChild(li);
});
}
// Qo'shish
document.querySelector("#qosh").addEventListener("click", () => {
const matn = input.value.trim();
if (matn === "") return;
vazifalar.push({ matn, bajarildi: false });
input.value = "";
saqla();
render();
});
// Enter bilan ham qo'shish
input.addEventListener("keydown", (e) => {
if (e.key === "Enter") document.querySelector("#qosh").click();
});
// Event delegation: bosilganda bajarildi/o'chirish
ul.addEventListener("click", (e) => {
// O'chirish tugmasi bosildimi?
if (e.target.dataset.ochir !== undefined) {
vazifalar.splice(Number(e.target.dataset.ochir), 1);
}
// Vazifa matni bosildimi -> bajarildi toggle
else if (e.target.tagName === "LI") {
const i = Number(e.target.dataset.index);
vazifalar[i].bajarildi = !vazifalar[i].bajarildi;
}
saqla();
render();
});
// Boshlang'ich render
render();
</script>
</body>
</html>
✅ 3-qism yakuni¶
Endi sen haqiqiy interaktiv sahifa qura olasan:
- DOM bilan elementlarni tanlash, matn/atribut/class o'zgartirish, yangi element yasash
- Events bilan tugma, klaviatura, forma hodisalariga javob berish
- Event delegation — eng muhim pattern (dinamik elementlar uchun)
- Forms validatsiyasi va FormData
- localStorage bilan ma'lumotni saqlash (obyekt — JSON orqali)
Va eng muhimi — bularning hammasini birlashtirib to'liq Todo-app yozding. Bu — frontend'ning "Hello World"i: render → event → state o'zgarishi → qayta render → saqlash. Aynan shu sikl Vue/React'da ham ishlaydi (faqat ular buni avtomatlashtiradi).
Keyingi qadam (4-qism) — Asinxron JS¶
Bu — eng muhim va eng chalkash qism. Server bilan gaplashish:
- Callbacks va Event Loop (JS qanday "kutadi")
- Promises — .then(), .catch()
- async/await — zamonaviy, toza usul
- Fetch API — backend'dan ma'lumot olish (real API'lar bilan)
Maslahat: 4-qismga o'tishdan oldin Todo-app'ni o'zing noldan, qarab emas, yoddan yozib ko'r. Agar yoza olsang — DOM, events va state'ni tushunding degani.
📚 README · ← 2-qism — Strukturalar · Keyingi: 4-qism — Asinxron JS →