Дарси 12 · 🏁 Лоиҳаи хурди №1
Лоиҳаи хурд: трекери вазифаҳо ё одатҳо
Аввалин лоиҳаи воқеӣ барои портфолио: барнома бо JavaScript-и холис, ки маълумоти шуморо ҳатто баъди аз нав бор шудани саҳифа дар хотир медорад. Чунин трекерҳо паси Todoist, Notion ва даҳҳо барномаҳои телефон истодаанд, ва имрӯз шумо трекери худро месозед, онро дар назди гурӯҳ ҳимоя мекунед ва ба GitHub бор мекунед.
Варианти лоиҳаро интихоб кардан ва онро ба 10–15 зервазифа бо баҳои вақт тақсим кардан
Барномаро гирди як объекти ҳолат ва функсияи render ҷамъ кардан
Шакл, вакилкунии ҳодисаҳо, филтрҳо ва захираро дар localStorage пайваст кардан
Code review-ро дар ҷуфт аз рӯи чек-лист гузаронидан ва эродҳоро ислоҳ кардан
Лоиҳаро дар 5 дақиқа ҳимоя кардан: нишон додан, кодро шарҳ додан, ба саволҳо ҷавоб додан
Лоиҳаро ба GitHub бор кардан ва чунон оро додан, ки нишон додан шармовар набошад
Бо ин саҳифа чӣ тавр кор кардан лозим
Имрӯз дарси-лоиҳа аст. Қисми болоии саҳифа — супориш, меъёрҳои баҳогузорӣ ва нақша. Дар миёна — гармкунӣ : вазифаҳои кӯтоҳ, ки аз онҳо трекер ҷамъ мешавад (ҳолат, кашидан, ҳодисаҳо, филтрҳо, захира). Ҳар кадом худкор санҷида мешавад, мисли дарсҳои гузашта. Минбаъд — қолаби оғозӣ дар қуттии санҷиш, чек-лист барои санҷиш дар ҷуфт, нақшаи ҳимоя ва бор кардан ба GitHub. Лоиҳаро шумо дар VS Code-и худ ҷамъ мекунед, ва дар ин ҷо машқ мекунед ва муқоиса мекунед.
01 Супориш: вариантро интихоб кунед
Лоиҳа аз он чи шумо дар дарсҳои 8–11 кардаед, ҷамъ мешавад: рӯйхат дар DOM, ҳодисаҳо, шакл, ҳолат дар як объект ва захира. Имрӯз мо ҳама чизро то барномаи корӣ мерасонем, якдигарро месанҷем ва ҳимоя мекунем. Яке аз ду вариантро интихоб кунед — мувофиқи ҳамон меъёрҳо баҳо медиҳем.
Варианти А. Трекери вазифаҳо
Рӯйхати корҳо: вазифа менависед, илова мекунед, иҷрошуда қайд мекунед, нест мекунед. Филтрҳои «Все / Активные / Готовые» ва ҳисобкунаки «Осталось: 3 из 5» ҳастанд.
Ниҳод: { id, title, done }
Варианти Б. Трекери одатҳо
Рӯйхати одатҳо («Читать 20 минут», «Тренировка»). Ҳар рӯз «анҷом шуд»-ро қайд кардан мумкин аст, барнома силсилаи рӯзҳои пай дар пай ва чанд одат имрӯз иҷро шудааст, нишон медиҳад.
Ниҳод: { id, name, days: ["2026-10-14", …] }
Вариантҳо аз рӯи мураккабӣ қариб баробаранд: дар одатҳо мантиқ мураккабтар (санаҳо ва силсила), дар вазифаҳо — ҳолатҳои намоиши бештар (филтрҳо). Агар шумо танҳо навакак бо эътимод код навиштан оғоз карда бошед — вазифаҳоро гиред. Мехоҳед чолиш — одатҳо. Ғояи худро пешниҳод кардан мумкин аст, аммо танҳо дар сурате ки аз рӯи ҳаҷм ҳамон қадар бошад ва шумо онро бо омӯзгор пеш аз оғози кор мувофиқа карда бошед.
Муқоиса аз ҳаёт
Дафтарчаеро тасаввур кунед, ки модар дар он менависад, ки дар бозор чӣ харидан лозим. Харидашударо хат зад — сабт монд, аммо дигар менамояд. Дафтарро баст, фардо кушод — сабтҳо ба ҷояш. Трекери шумо — ҳамин гуна дафтар аст: ҳолат — ин сабтҳост, render — онҳо дар саҳифа чӣ гуна менамоянд, localStorage — худи дафтар, ки ҳангоми бастан гум намешавад.
Шумо дар охир чиро нишон медиҳед
Барномаи кор — дар браузер бе хато дар консол кушода мешавад.
Репозиторий дар GitHub бо код ва README (ин чист, чӣ тавр оғоз кардан, скриншот).
Ҳимоя дар 5 дақиқа — намоиш, шарҳи код ва ҷавоб ба саволҳо.
Қоидаҳои курс дар ин ҷо ҳам амал мекунанд
ЗС-ро истифода бурдан мумкин аст (мо ҳатто дар поён омӯхтани онро мекунем), аммо мувофиқи қоидаҳои курс: аввал 15 дақиқа худатон кӯшиш мекунед, коде, ки сатр ба сатр шарҳ дода наметавонед, ворид намекунед, ва дар ҳимоя омӯзгор ҳақ дорад хоҳиш кунад, ки ҳар сатрро шарҳ диҳед. Натавонистед — холҳо барои ин қисм кам карда мешаванд.
02 Талабот: MVP ва бонусҳо
MVP (minimum viable product) — версияи ҳадди ақал, ки аллакай муфид аст ва аз аввал то охир кор мекунад. Аввал онро пурра месозем, ва танҳо баъд вақтро ба оро сарф мекунем. Лоиҳа бе MVP баҳои баланд намегирад, ҳар қадар бонус дошта бошад.
MVP — ҳатмӣ барои ҳар ду вариант
№ Варианти А — вазифаҳо Варианти Б — одатҳо 1 Шакли иловаи вазифа (майдон + тугма, Enter низ кор мекунад) Шакли иловаи одат (майдон + тугма) 2 Санҷиш: сатри холӣ ва танҳо фосилаҳо илова намешаванд, корбар паёмро мебинад Ҳамон + одатро бо номи аллакай мавҷуда илова кардан мумкин нест 3 Қайд кардани вазифа ҳамчун иҷрошуда (ва баръакс) бо клик Қайди «имрӯз анҷом шуд» (ва бардоштани қайд) 4 Нест кардани вазифа Нест кардани одат 5 Филтрҳои «Все / Активные / Готовые» Филтри «Все / Не сделано сегодня / Сделано сегодня» 6 Ҳисобкунаки «Осталось: N из M» ва паём, вақте рӯйхат холӣ аст Силсилаи рӯзҳои пай дар пай дар ҳар одат ва ҳисобкунаки «Сегодня: N из M» 7 Ҳамаи маълумот дар localStorage захира мешавад ва баъди аз нав бор шудан (F5) барқарор мешавад. Маълумоти шикаста ё холӣ барномаро намеафтонад. 8 Код аз рӯи нақша сохта шудааст: ҳолат → функсияҳо болои ҳолат → render → коркардкунандаҳои ҳодисаҳо . Бе тағйирёбандаҳои глобалии «партов», бе нусхабардории беҳуда.
Бонусҳо — баъди MVP
Таҳрир: клики дучанда ба матн онро ба майдони воридкунӣ табдил медиҳад (Enter — захира, Esc — бекор).
Тугмаи «Очистить выполненные» бо тасдиқ.
Ҷустуҷӯ дар рӯйхат дар вақти воқеӣ (ҳодисаи input).
Афзалиятҳо ё категорияҳо бо нишонаҳои рангин.
Мавзӯи торик бо захираи интихоб.
Мураттабсозӣ: аз рӯи алифбо, аз рӯи санаи илова.
Барои одатҳо: ҳафта дар шакли 7 нуқта бо қайдҳо аз рӯи рӯзҳо ва «беҳтарин силсила».
Маслиҳат
Бонусҳоеро интихоб кунед, ки шумо метавонед дар ҳимоя шарҳ диҳед . Як бонуси оддӣ, ки шумо ҳар сатри онро мефаҳмед, аз се пораи «сеҳрнок»-и код аз чат бо ЗС қиматтар аст.
03 Лоиҳа чӣ тавр баҳо дода мешавад (0–100)
Лоиҳаи хурд аз рӯи шкалаи 0–100 баҳо дода мешавад, чунон ки дар қоидаҳои курс навишта шудааст. Баҳо аз ҳафт меъёр иборат аст:
Меъёр Холҳо Ҳадди аксар мегузорем, агар… Қисман, агар… Функсионалияти MVP 25 ҳамаи 6 банди MVP кор мекунанд (илова, санҷиш, қайд, нест кардан, филтр, ҳисобкунак): ~4 хол барои ҳар банд як қисми бандҳо бо хатоҳо кор мекунад ё нест DOM ва кашидан 15 интерфейс аз ҳолат бо функсияи render сохта мешавад; баъди даъвати такрорӣ такрор нест; барои матни корбар ба ҷои innerHTML textContent истифода мешавад як қисми DOM дар ҷойҳои гуногун «бо даст» ислоҳ карда мешавад Ҳодисаҳо ва шаклҳо 15 preventDefault ҳаст, санҷиш бо паёми фаҳмо, вакилкунии ҳодисаҳо дар рӯйхат, Enter ва тугма яксон кор мекунандбарои ҳар элементи рӯйхат коркардкунандаи алоҳида, санҷиш расмӣ Ҳолат ва localStorage 15 як объекти ҳолат, захира тавассути JSON, try/catch ҳангоми хондан, маълумот аз F5 мегузарад захира мешавад, аммо маълумоти шикаста барномаро меафтонад Сохтори код 10 функсияҳои кӯтоҳ бо номҳои фаҳмо, такрор нест, коди мурда ва console.log-и зиёдатӣ нест, константаҳо ба ҷои сатрҳои «ҷодугарӣ» як «функсияи ҳаюло» ё нусхабардорӣ ҳаст Интерфейс 5 озода менамояд, дар телефон кор мекунад (320–400 px), ҳолатҳои «холӣ», :hover, :focus ҳастанд кор мекунад, аммо мисли чернавик менамояд Ҳимоя 15 дар 5 дақиқа ҷойгир шуд, сенарияро нишон дод, қисмҳои асосии кодро шарҳ дод ва ба саволҳо ҷавоб дод бо суханони умумӣ шарҳ медиҳед, дар «ин сатрро шарҳ деҳ» гум шуд ҶАМЪ 100
Бонусҳо то +5 хол илова мекунанд, аммо натиҷа аз 100 зиёд буда наметавонад. Яъне бонусҳо метавонанд талафоти хурдро дар меъёрҳои асосӣ ҷуброн кунанд.
Чӣ холҳоро кам мекунад
Кодро шарҳ дода наметавонед — дар меъёре, ки қисми нофаҳмо ба он тааллуқ дорад, холҳо гум мекунед (қоидаи курс №2 ва №3).
Ба мӯҳлат супорида нашуд — то −10 хол, бо мувофиқа бо омӯзгор.
Код пурра аз донишҷӯи дигар ё аз чат бе фаҳмиш нусха шудааст — 0 барои лоиҳа. Ба якдигар кӯмак кардан мумкин ва лозим аст, аммо ҳар кас аз они худро менависад ва мефаҳмад.
Ин ба баҳои ниҳоии курс чӣ тавр таъсир мерасонад
Ҷузъи курс Вазн Чӣ тавр ҳисоб мешавад Ҳозиршавӣ 15% ҳиссаи дарсҳои иштирокшуда Вазифаҳои хонагӣ 30% холи миёна барои 24 вазифаи хонагӣ (0–10) Лоиҳаҳои хурд (2 адад) 25% миёна барои лоиҳаи хурд 1 ва 2 (0–100) Лоиҳаи ниҳоӣ 30% ҳимоя дар дарси 21 (0–100)
Мисол: барои лоиҳаи хурди 1 шумо 82 гирифтед, барои лоиҳаи хурди 2 — 90. Миёна — 86, ва ба натиҷаи курс 86 × 25% = 21.5 хол меравад. Барои сертификат ҳар ду лоиҳаи хурдро супурдан лозим аст.
Холҳо Баҳо 90–100 Аъло 75–89 Хуб 60–74 Қаноатбахш камтар аз 60 Аттестатсия нашудааст
04 Декомпозитсия: лоиҳаро якҷоя бо ЗС тақсим мекунем
Хатои асосии навомӯз пеш аз лоиҳаи калон — нишаста «ҳама чизро якбора» навиштан оғоз кардан. Баъди як соат код ба бесаранҷомӣ табдил меёбад, нофаҳмо аст, ки чӣ аллакай кор мекунад, ва мехоҳӣ ҳамаро партоӣ. Касбиён дигар хел мекунанд: аввал вазифаро ба қадамҳои хурд тақсим мекунанд , вақти ҳар кадомро баҳо медиҳанд ва пай дар пай мераванд. Ин декомпозитсия номида мешавад.
Муқоиса аз ҳаёт
Палави тӯйро барои 200 нафар «ягон тавр» намепазанд. Аввал рӯйхат: гӯшт ва биринҷ харидан, сабзиро буридан, оташ афрӯхтан, зирвакро андохтан, биринҷро резондан, ба дам гузоштан. Барои ҳар қадам — вақт ва масъул. Лоиҳа — ҳамон палав: мақсади калон, аз қадамҳои хурд.
Блоки ЗС-и дарс: вазифаи калон — нофаҳмо, аз куҷо оғоз кардан
Ин вазъияти №10 аз китобхонаи промптҳои курс аст. ЗС рӯйхати қадамҳоро олӣ пешниҳод мекунад, аммо тартиб, зиёдатӣ ва баҳои вақтро шумо месанҷед . Аз версияи бе қоида оғоз кунед, баъд — бо формулаи курс: контекст → вазифа → маҳдудиятҳо → формат → санҷиш.
трекери вазифаҳоро чӣ тавр сохтанНусха бардоштан
Контекст: ман донишҷӯи курси JavaScript ҳастам, лоиҳаи таълимии «трекери вазифаҳо»-ро бо JS-и холис бе китобхонаҳо ва фреймворкҳо менависам. Аллакай медонам: DOM, ҳодисаҳо, шаклҳо, localStorage, объектҳо ва массивҳо.
Вазифа: лоиҳаро ба 10–15 зервазифаи 20–40 дақиқагӣ ба тартиби иҷро тақсим кун.
Маҳдудиятҳо: дар MVP танҳо илова, қайд, нест кардан, филтрҳо, ҳисобкунак ва захира. Ягон китобхона. Бонусҳоро бо рӯйхати алоҳида дар охир баровар.
Формати ҷавоб: рӯйхати рақамдор. Дар ҳар банд: ном, баъди он чӣ бояд кор кунад, баҳо бо дақиқа.
Санҷиш: баъди рӯйхат 3 ҷойро ном бар, ки навомӯз дар ин лоиҳа бештар хато мекунад.Нусха бардоштан
Промпти аввал суханони умумӣ медиҳад ва шояд фавран тамоми кодро, ки шумо шарҳ дода наметавонед. Дуюм нақшае медиҳад, ки бо он кор кардан мумкин аст. Аммо ин танҳо чернавик аст. Ба намунаи натиҷа баъди ислоҳи шумо нигоҳ кунед:
Намунаи нақша барои варианти А (дар маҷмӯъ 6 соат)
№ Зервазифа Вақт Баъди он чӣ кор мекунад 1 Аломатгузорӣ: шакл, рӯйхат, филтрҳо, ҳисобкунак 30 дақ саҳифа мисли трекер менамояд, аммо «мурда» аст 2 Модели маълумот: объекти state ва формати вазифа 20 дақ ҳал шудааст, ки чӣ ва дар кадом майдонҳо нигоҳ дошта мешавад 3 Функсияҳо болои ҳолат: addTask, toggleTask, removeTask 30 дақ мантиқро бе саҳифа дар консол санҷидан мумкин аст 4 Функсияи render(): рӯйхат аз ҳолат 35 дақ вазифаҳо аз массив дар саҳифа пайдо мешаванд 5 Ҳодисаи submit-и шакл + санҷиш 30 дақ вазифаро илова кардан мумкин аст, холиро — не 6 Вакилкунӣ: клик ба вазифа ва ба «✕» 30 дақ қайд ва нест кардан кор мекунанд 7 Филтрҳои «Все / Активные / Готовые» 25 дақ тугмаҳо рӯйхати нишондодашударо иваз мекунанд 8 Ҳисобкунак ва паёми «Пока нет задач» 20 дақ рӯйхати холӣ ва пур дуруст менамоянд 9 saveState / loadState + try/catch30 дақ баъди F5 ҳама чиз ба ҷояш 10 Услубҳо: .done, :hover, телефон 30 дақ барнома хушманзара аст 11 Санҷиши дастӣ аз рӯи чек-лист, ислоҳи хатоҳо 30 дақ дар консол хато нест 12 Рефакторинг: номҳо, такрор, коди мурда 20 дақ код аз боло ба поён хонда мешавад 13 README ва скриншот 15 дақ репозиторий фаҳмо аст 14 Бор кардан ба GitHub 15 дақ лоиҳа аз рӯи истинод дастрас аст
Бо ҷавоби ЗС чӣ мекунед — қадам ба қадам
Зиёдатиро хат занед. Агар ЗС «Webpack-ро танзим кун» ё «React-ро пайваст кун»-ро пешниҳод кард — ин дар бораи лоиҳаи мо нест. Мо бо JS-и холис.
Тартибро санҷед. «Захира»-ро пеш аз «ҳолат» кардан мумкин нест: аввал бояд донист, чиро захира кардан. Ҳар қадам бояд ба қадамҳои тайёри пешина такя кунад.
Вақтро худатон баҳо диҳед. ЗС намедонад, ки барои шумо чӣ қадар вақт меравад. То ҳол таҷриба нест, баҳои ӯро ба 1.5 зарб кунед. Ҳар қадаме, ки аз 40 дақиқа дарозтар аст — боз тақсим кунед.
Ҳар қадам бояд натиҷаи намоён диҳад. «Дар бораи меъморӣ фикр кардан» — қадам нест. «Функсияи addTask санҷишро дар консол мегузарад» — қадам аст.
MVP-ро аз бонусҳо ҷудо кунед. Бонусҳоро танҳо вақте иҷро мекунем, ки ҳама чизи MVP кор мекунад.
Нақшаро нависед дар файли PLAN.md ё шарҳ — ва иҷрошударо қайд кунед. Ҳар нишона — пешрафти намоён, ва он ангезаро нигоҳ медорад.
Амалиёт: ҳисоб кардани нақшаро меомӯзем
Нақша низ маълумот аст. Онро бо воситаҳои JavaScript ҳисоб мекунем.
ВАЗИФАИ 4.1 Марҳилаи аввал чӣ қадар мегирад осон
Массиви зервазифаҳо бо баҳои вақт бо дақиқа дода шудааст. Ҷамъро ҳисоб кунед ва сатри намуди Всего: 175 мин = 2.9 ч-ро чоп кунед. Соатҳоро то як рақами баъди вергул мудаввар кунед (toFixed(1)).
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const plan = [
{ title: "Разметка страницы" , min: 20 },
{ title: "Объект состояния" , min: 25 },
{ title: "Функция render" , min: 40 },
{ title: "Форма добавления" , min: 30 },
{ title: "Отметка выполненных" , min: 25 },
{ title: "Сохранение в localStorage" , min: 35 },
];
// ҷамъи дақиқаҳоро ҳисоб кунед ва сатри натиҷавиро чоп кунед
Натиҷаи интизоршаванда Всего: 175 мин = 2.9 ч
Ишора 1 Ҷамъи ададҳоро аз массиви объектҳо усули reduce бо қимати оғозии 0 ҷамъ мекунад: дар ҳар қадам item.min-ро илова мекунем.
Ишора 2 plan.reduce((sum, item) => sum + item.min, 0). Соатҳо — ин total / 60 аст, ва .toFixed(1) як рақамро мегузорад.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 4.2 Қадамҳои хеле калон миёна
Қоида: ҳар қадаме, ки аз 40 дақиқа дарозтар аст, бояд тақсим шавад. Барои ҳар чунин қадам як сатр дар формати Разбить: Название (N мин) чоп кунед ва дар охир — чанд қадамро тақсим кардан лозим аст: Нужно разделить: 2.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const plan = [
{ title: "Разметка" , min: 20 },
{ title: "Фильтры и счётчики" , min: 90 },
{ title: "Форма" , min: 30 },
{ title: "Сохранение и загрузка" , min: 60 },
{ title: "Стили" , min: 25 },
];
// қадамҳои аз 40 дақиқа дарозтарро ёбед
Натиҷаи интизоршаванда Разбить: Фильтры и счётчики (90 мин)
Разбить: Сохранение и загрузка (60 мин)
Нужно разделить: 2
Ишора 1 Аввал массивро филтр кунед: filter танҳо қадамҳоеро мегузорад, ки дар онҳо min аз 40 зиёд аст. Натиҷаро ба тағйирёбанда гузоред.
Ишора 2 Бо forEach аз болои массиви филтршуда гузаред ва сатрро бо қолаб чоп кунед. Миқдор — ин .length-и ҳамон массив аст.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 4.3 MVP ва бонусҳо алоҳида осон
Дар нақша ҳар қадам аломати bonus дорад. Вақти MVP ва вақти бонусҳоро алоҳида ҳисоб кунед. Функсияи ёридиҳандаи ҷамъро нависед, то коди такрор нашавад.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const plan = [
{ title: "Разметка" , min: 20 , bonus: false },
{ title: "Функция render" , min: 40 , bonus: false },
{ title: "Форма добавления" , min: 30 , bonus: false },
{ title: "Сохранение" , min: 50 , bonus: false },
{ title: "Тёмная тема" , min: 25 , bonus: true },
{ title: "Поиск по задачам" , min: 30 , bonus: true },
];
// const sumMin = (list) => ...
// console.log(`MVP: ... мин`);
// console.log(`Бонус: ... мин`);
Натиҷаи интизоршаванда MVP: 140 мин
Бонус: 55 мин
Ишора 1 Функсия массивро мегирад ва ҷамъи майдони min-ро бармегардонад. Онро ду маротиба даъват кунед — барои массивҳои гуногуни филтршуда.
Ишора 2 MVP — ин plan.filter(i => !i.bonus), бонусҳо — plan.filter(i => i.bonus).
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
05 Гармкунии 1. Ҳолат — дили трекер
Нақша ҳаст, ба код мегузарем. Аз асосӣ оғоз мекунем — ҳолат (дарси 11). Ҳар чизе, ки барнома «медонад», дар як объект ҷой дорад: рӯйхати вазифаҳо, филтри интихобшуда, рақами навбатӣ. Саҳифа — танҳо тасвири ин объект аст.
Ҳолати трекери вазифаҳо · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const state = {
tasks: [
{ id: 1 , title: "Купить лепёшки" , done: false },
{ id: 2 , title: "Сделать ДЗ" , done: true },
],
filter: "all" , // "all" | "active" | "done"
nextId: 3 , // кадом id-ро вазифаи навбатӣ мегирад
};
console.log (state.tasks.length);
console.log (state);
Чаро майдони алоҳидаи nextId? Агар tasks.length + 1 гиранд, баъди нест кардани вазифа рақамҳо такрор мешаванд. Дар ин бора мо боз дар вақти аз назар гузаронӣ сухан меронем. Ҳоло — қоидаи асосӣ: функсияҳо болои ҳолат объекти кӯҳнаро намерасонанд, балки навро бармегардонанд .
Функсияи тоза: ҳолати нав бармегардонад · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
function addTask (state, title) {
return {
... state, // ҳама дигарро нусха мекунем
tasks: [... state.tasks, { id: state.nextId, title, done: false }], // массиви нав
nextId: state.nextId + 1 ,
};
}
const s1 = { tasks: [], filter: "all" , nextId: 1 };
const s2 = addTask (s1, "Плов" );
console.log (s1.tasks.length, s2.tasks.length); // 0 1 — ҳолати кӯҳна тағйир наёфт
Муқоиса аз ҳаёт
Муҳосиб дар мағозаи бозор сатрҳои кӯҳнаро дар журнал пок намекунад, балки навашро илова мекунад. Ҳамеша метавон дид, ки пештар чӣ тавр буд. Функсия, ки ҳолати навро бармегардонад, ҳамин тавр рафтор мекунад: кӯҳна бе тағйир мемонад, бинобар ин хатоҳоро ёфтан осонтар аст.
Хатои маъмул
Ҳолатро «дар ҷо» тағйир додан: state.tasks.push(...) дар дохили функсия. Кор мекунад, аммо рӯзе мебинед, ки шумо ду ҳолати «якхела» доред, ки ҳамзамон тағйир меёбанд, ва намефаҳмед, чаро. Одати «навро бармегардонам» инро намегузорад.
Барои муфассалтар хондан: learn.javascript.ru — методы массивов · MDN — оператор расширения (spread)
Амалиёт: мустаҳкам мекунем
«Ядро»-и трекерро ҷамъ мекунем — функсияҳо болои ҳолат. Онҳоро баъдтар ба лоиҳа ҳамон тавр интиқол додан мумкин аст.
ВАЗИФАИ 5.1 Чопро пешгӯӣ кунед осон
Аввал бе иҷро пешгӯӣ кунед, ки код чӣ чоп мекунад, баъди он ки шумо вазифаи сеюми { id: 3, title: "Позвонить маме", done: true }-ро ба массив илова мекунед (push — дар ҷои шарҳ). Чор ҷавобро дар коғаз нависед, баъд иҷро кунед ва муқоиса кунед.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const state = {
tasks: [{ id: 1 , title: "Купить лепёшки" , done: false }],
filter: "all" ,
};
state.tasks.push ({ id: 2 , title: "Сделать ДЗ" , done: true });
state.filter = "done" ;
// дар ин ҷо вазифаи сеюмро илова кунед
console.log (state.tasks.length);
console.log (state.tasks[1 ].title);
console.log (state.filter);
console.log (state.tasks.filter ((t) => t.done).length);
Натиҷаи интизоршаванда 3
Сделать ДЗ
done
2
Ишора 1 Индексҳои массив аз сифр оғоз мешаванд: tasks[1] — вазифаи дуюм аст.
Ишора 2 Вазифаи сеюм ҳамон тавр илова мешавад, мисли дуюм: state.tasks.push({ ... }). Вазифаҳои иҷрошуда баъд аз ин дутоанд (id 2 ва id 3).
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 5.2 Фабрикаи ҳолат осон
Функсияи createState()-ро нависед, ки объекти холии нави ҳолатро бармегардонад: tasks — массиви холӣ, filter — "all", nextId — 1. Ҳар даъват бояд объекти новобаста диҳад.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
// function createState() { ... }
const a = createState ();
const b = createState ();
a.tasks.push ({ id: 1 , title: "тест" , done: false });
console.log (JSON.stringify (a));
console.log (JSON.stringify (b));
Натиҷаи интизоршаванда {"tasks":[{"id":1,"title":"тест","done":false}],"filter":"all","nextId":1}
{"tasks":[],"filter":"all","nextId":1}
Ишора 1 Функсия бояд ҳар дафъа объектро аз нав созад, на як ва ҳамонро, ки дар берун эълон шудааст, диҳад.
Ишора 2 Бадани функсия — як return { tasks: [], ... };. Литерали нави объект ҳангоми ҳар даъват — ҳамин объекти нав аст.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 5.3 addTask бе мутатсияҳо миёна
addTask(state, title)-ро нависед. Он фосилаҳои канории номро мебарорад (trim), ҳангоми сатри холӣ ҳолатро бе тағйир бармегардонад, вагарна ҳолати нав -ро бо вазифаи иловашудаи { id, title, done: false } ва nextId-и афзудашуда бармегардонад. Ҳолати кӯҳнаро тағйир додан мумкин нест.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const createState = () => ({ tasks: [], filter: "all" , nextId: 1 });
// function addTask(state, title) { ... }
let s = createState ();
s = addTask (s, " Купить лепёшки " );
s = addTask (s, " " );
s = addTask (s, "Сделать ДЗ" );
console.log (s.tasks.map ((t) => `${t.id}:${t.title}` ).join (" | " ));
console.log (s.nextId);
const before = s;
const after = addTask (s, "Позвонить маме" );
console.log (before.tasks.length, after.tasks.length);
Натиҷаи интизоршаванда 1:Купить лепёшки | 2:Сделать ДЗ
3
2 3
Ишора 1 Аввал const clean = title.trim();, баъд return state-и барвақт, агар clean сатри холӣ бошад.
Ишора 2 { ...state, tasks: [...state.tasks, новаяЗадача], nextId: state.nextId + 1 }-ро баргардонед. Вазифаи нав id: state.nextId мегирад.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 5.4 Хаторо ёбед: қайд на ба он ҷо миёна
Функсияи toggleTask бояд done-ро танҳо дар вазифа бо id-и лозимӣ баръакс кунад ва ҳолати аслиро тағйир надиҳад . Ҳоло он коре мекунад, ки лозим нест: «пеш» ва «баъд» нодуруст менамоянд. Ду хаторо ёбед.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
function toggleTask (state, id) {
return {
... state,
tasks: state.tasks.map ((t) => {
if (t.id = id) {
t.done = !t.done;
}
return t;
}),
};
}
const show = (s) => s.tasks.map ((t) => t.id + (t.done ? "✓" : "✗" )).join (" " );
const s1 = {
tasks: [
{ id: 1 , title: "Плов" , done: false },
{ id: 2 , title: "Чой" , done: false },
{ id: 3 , title: "Самбуса" , done: true },
],
};
const s2 = toggleTask (s1, 2 );
console.log ("до:" , show (s1));
console.log ("после:" , show (s2));
Натиҷаи интизоршаванда до: 1✗ 2✗ 3✓
после: 1✗ 2✓ 3✓
Ишора 1 Ба шарти if (t.id = id) бодиққат нигоҳ кунед: он ҷо чанд аломати баробарӣ ҳаст? Як аломат чӣ мекунад?
Ишора 2 Хатои дуюм: t.done = !t.done объектеро тағйир медиҳад, ки ба ҳолати кӯҳна тааллуқ дорад. Ба ҷои ин нусхаро баргардонед: { ...t, done: !t.done }, ва вазифаҳои боқимонда — чун ҳастанд.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 5.5 Нест кардан, тоза кардан, омор душвор
Се функсияро нависед, ки ҳолати аслиро тағйир надиҳанд:
removeTask(state, id) — ҳолат бе вазифа бо ин id;
clearDone(state) — ҳолат бе вазифаҳои иҷрошуда;
getStats(state) — объекти { total, done, left }.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const s = {
tasks: [
{ id: 1 , title: "Плов" , done: true },
{ id: 2 , title: "Чой" , done: false },
{ id: 3 , title: "Самбуса" , done: true },
{ id: 4 , title: "Курутоб" , done: false },
],
};
// removeTask, clearDone, getStats
const ids = (st) => st.tasks.map ((t) => t.id).join (" " );
console.log (ids (removeTask (s, 2 )));
console.log (ids (clearDone (s)));
const st = getStats (s);
console.log (`Всего: ${st.total}, сделано: ${st.done}, осталось: ${st.left}` );
console.log (s.tasks.length);
Натиҷаи интизоршаванда 1 3 4
2 4
Всего: 4, сделано: 2, осталось: 2
4
Ишора 1 Ҳам removeTask, ҳам clearDone — ин { ...state, tasks: state.tasks.filter(...) } аст. Танҳо шарт дар filter фарқ мекунад.
Ишора 2 Дар getStats total ва done-ро ҳисоб кунед (тавассути filter ва length), ва left бо тарҳ ҳосил мешавад.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
06 Гармкунии 2. Функсияи render
Ҳолат худ ба худ дар экран намоён нест. Функсияе лозим аст, ки ҳолатро мегирад ва онро дар DOM мекашад . Қоидаи ин функсия оддӣ аст: рӯйхатро пок кардан ва аз нав сохтани он аз ҳолат. Намеҷӯем, ки кадом элемент тағйир ёфт, якто-якто ислоҳ намекунем — ҳама чиз аз сифр. Барои трекери хурд ин зуд ва боэътимод аст.
Ҳар блоки код дар ин саҳифа дар «саҳифа»-и холии худ кор мекунад, ки дар он document ҳаст. Бинобар ин мо метавонем элементҳоро тавассути document.createElement созем ва он чиро, ки мехоҳем санҷем, ба консол чоп кунем.
render: пок кардем ва аз нав сохтем · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
function createTaskItem (task) {
const li = document.createElement ("li" );
li.textContent = task.title;
if (task.done) li.classList.add ("done" );
return li;
}
function render (state, list) {
list.innerHTML = "" ; // 1. пок кардем
state.tasks.forEach ((task) => list.append (createTaskItem (task))); // 2. аз нав сохтем
}
const list = document.createElement ("ul" );
render ({ tasks: [{ title: "Плов" }, { title: "Чой" }] }, list);
render ({ tasks: [{ title: "Плов" }, { title: "Чой" }] }, list); // бори дуюм: такрор нест
console.log (list.children.length); // 2, на 4
Муқоиса аз ҳаёт
Дар чойхона меню бо бӯр дар тахта навишта мешавад. Вақте таом тамом шуд, ҳарфро паси ҳарф пок намекунанд, балки тахтаро пок карда, менюи имрӯзаро аз нав менависанд. render — ин латта ва бӯр дар як зарф аст: пок кардем, аз рӯи ҳолат навиштем.
Ду хатои классикии render
1. Рӯйхатро пок кардан фаромӯш шуд — баъди ҳар даъват вазифаҳо дучанд мешаванд. 2. Матни корбарро тавассути innerHTML гузоштан — агар одам <b> ё бадтарро ворид кунад, коди бегона ба саҳифа меафтад. Барои матн textContent-ро истифода баред: он ҳама чизро мисли ҳарфҳои оддӣ нишон медиҳад.
Хато: рӯйхат пок намешавад · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
function render (tasks, list) {
tasks.forEach ((title) => {
const li = document.createElement ("li" );
li.textContent = title;
list.append (li);
});
}
const list = document.createElement ("ul" );
render (["Плов" , "Чой" ], list);
render (["Плов" , "Чой" ], list);
console.log (list.children.length); // 4 — такрор!
Барои муфассалтар хондан: learn.javascript.ru — изменение документа · MDN — textContent
Амалиёт: мустаҳкам мекунем
ВАЗИФАИ 6.1 Элементи як вазифа осон
createTaskItem(task)-ро нависед: он элементи <li>-ро бо синфи task, матни вазифа ва атрибути data-id (тавассути dataset.id) бармегардонад. Дар вазифаи иҷрошуда боз синфи done илова мешавад.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
// function createTaskItem(task) { ... }
const li1 = createTaskItem ({ id: 7 , title: "Купить лепёшки" , done: false });
const li2 = createTaskItem ({ id: 8 , title: "Сделать ДЗ" , done: true });
console.log (li1.tagName, li1.className, li1.dataset.id, li1.textContent);
console.log (li2.className);
Натиҷаи интизоршаванда LI task 7 Купить лепёшки
task done
Ишора 1 Элементи document.createElement("li")-ро созед, li.className = "task"-ро гузоред, баъд бо шарт li.classList.add("done").
Ишора 2 li.dataset.id = task.id; атрибути data-id-ро месозад. return li;-ро фаромӯш накунед.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 6.2 render бе такрор миёна
render(state, list)-ро ба итмом расонед: он рӯйхатро пок мекунад ва барои ҳар вазифа аз state.tasks як элемент илова мекунад. Даъвати дуюм бо ҳолати дигар бояд мундариҷаро иваз кунад, на ба он илова.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
function createTaskItem (task) {
const li = document.createElement ("li" );
li.textContent = task.title;
return li;
}
// function render(state, list) { ... }
const list = document.createElement ("ul" );
const titles = () => [... list.children].map ((li) => li.textContent).join (", " );
render ({ tasks: [{ title: "Плов" }, { title: "Чой" }, { title: "Самбуса" }] }, list);
console.log (list.children.length, titles ());
render ({ tasks: [{ title: "Чой" }, { title: "Самбуса" }] }, list);
console.log (list.children.length, titles ());
Натиҷаи интизоршаванда 3 Плов, Чой, Самбуса
2 Чой, Самбуса
Ишора 1 Сатри аввали функсия — пок кардан: list.innerHTML = "";. Дар ин ҷо innerHTML бехатар аст: мо сатри холиро менависем, на маълумоти корбарро.
Ишора 2 Баъд state.tasks.forEach(task => list.append(createTaskItem(task))).
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 6.3 Ҳолати холӣ миёна
Агар вазифаҳо набошанд, рӯйхат набояд холӣ ва «мурда» бошад: як элементи <li class="empty">-ро бо матни Пока нет задач. Добавьте первую! нишон диҳед. Ҳамин ки вазифаҳо пайдо мешаванд — паём нест мешавад.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
function createTaskItem (task) {
const li = document.createElement ("li" );
li.className = "task" ;
li.textContent = task.title;
return li;
}
function render (state, list) {
list.innerHTML = "" ;
// агар вазифаҳо набошанд — паёмро нишон диҳед ва бароед
state.tasks.forEach ((task) => list.append (createTaskItem (task)));
}
const list = document.createElement ("ul" );
const info = () =>
`${list.children.length} ${list.firstElementChild.className} ${list.firstElementChild.textContent}` ;
render ({ tasks: [] }, list);
console.log (info ());
render ({ tasks: [{ title: "Купить хлеб" }] }, list);
console.log (info ());
render ({ tasks: [] }, list);
console.log (info ());
Натиҷаи интизоршаванда 1 empty Пока нет задач. Добавьте первую!
1 task Купить хлеб
1 empty Пока нет задач. Добавьте первую!
Ишора 1 Баъди пок кардан state.tasks.length === 0-ро санҷед. Агар ҳа — li созед, синф ва матнро гузоред, ба рӯйхат илова кунед.
Ишора 2 Фавран баъди илова кардани паём return гузоред, то боқимонда коди функсия иҷро нашавад.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 6.4 Сӯрохро ёбед: HTML-и бегона дар саҳифа миёна
Корбар номи вазифаи <b>срочно!</b>-ро ворид кард. Барнома бояд онро ҳамчун матн нишон диҳад, на ба элементи ғафс табдил диҳад. Ҳоло дар createTaskItem сӯрох ҳаст: дар дохил теги воқеии <b> пайдо мешавад. Як сатрро ислоҳ кунед.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
function createTaskItem (task) {
const li = document.createElement ("li" );
li.innerHTML = task.title;
return li;
}
const li = createTaskItem ({ title: "<b>срочно!</b>" });
console.log (li.children.length); // чанд элементи дарунмонда?
console.log (li.textContent);
console.log (li.querySelector ("b" )); // бояд null бошад
Натиҷаи интизоршаванда 0
<b>срочно!</b>
null
Ишора 1 innerHTML сатрро ҳамчун аломатгузорӣ таҳлил мекунад, бинобар ин матни <b> ба теги воқеӣ табдил меёбад. Хосияте лозим аст, ки ҳама чизро ҳамчун матни оддӣ мефаҳмад.
Ишора 2 innerHTML-ро ба textContent иваз кунед. Боқимонда кодро тағйир додан лозим нест.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
07 Гармкунии 3. Шакл, клик ва вакилкунӣ
Ҳолат ҳаст, кашидан ҳаст. Боқӣ мондааст, ки интерфейсро зинда кунем: ирсоли шакл ва кликҳо ба вазифаҳоро бигирем. Дар лоиҳа айнан ду коркардкунандаи муҳим хоҳад буд: submit дар шакл ва click дар рӯйхат.
Шакл: submit + preventDefault + санҷиш
Коркардкунандаи submit · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const form = document.createElement ("form" );
form.innerHTML = '<input name="title"><button>Добавить</button>' ;
const input = form.querySelector ("input" );
form.addEventListener ("submit" , (event) => {
event.preventDefault (); // намегузорем, ки браузер саҳифаро аз нав бор кунад
const title = input.value.trim ();
if (!title) {
console.log ("Введите название" ); // дар лоиҳа — паём дар зери майдон
return ;
}
console.log ("Добавляем:" , title);
input.value = "" ;
});
input.value = " " ;
form.dispatchEvent (new Event ("submit" , { cancelable: true })); // пахшро тақлид мекунем
input.value = "Купить хлеб" ;
form.dispatchEvent (new Event ("submit" , { cancelable: true }));
Ҳодисаи submit ҳам ҳангоми клик ба тугма ва ҳам ҳангоми пахши Enter дар майдон кор мекунад: алоҳида шунидани клавиша лозим нест. Дар ин ҷо мо тугмаро тавассути dispatchEvent «мепахшем», зеро дар машқҳо саҳифаи зинда нест.
Рӯйхат: як коркардкунанда барои ҳама (вакилкунӣ)
Хатои аз ҳама маъмули навомӯзон — ба ҳар тугмаи «✕» ҳангоми сохтан addEventListener овехтан. Аммо ҳангоми ҳар render элементҳо аз нав сохта мешаванд, ва коркардкунандаҳо гум мешаванд ё зиёд мешаванд. Ҳалли дарси 9 — вакилкунӣ : як коркардкунанда дар падари умумии <ul>, ва дар дохил мебинем, ки маҳз ба куҷо клик карданд (event.target).
Вакилкунӣ: як коркардкунанда дар рӯйхат · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const list = document.createElement ("ul" );
list.innerHTML = `
<li data-id="1">Плов <button data-action="delete">✕</button></li>
<li data-id="2">Чой <button data-action="delete">✕</button></li>` ;
list.addEventListener ("click" , (event) => {
const btn = event.target.closest ("button[data-action='delete']" );
if (!btn) return ; // на ба тугмаи нест кардан клик карданд
const li = btn.closest ("li" );
console.log ("Удаляем задачу" , li.dataset.id);
li.remove ();
});
list.querySelector ("button" ).click ();
console.log (list.children.length); // 1
Муқоиса аз ҳаёт
Дар курс дар назди ҳар аудитория посбон намегузоранд — як маъмур дар даромадгоҳ мебинад, кӣ ба куҷо меравад. Дар ин ҷо низ ҳамин тавр: як коркардкунанда дар рӯйхат, ва event.target.closest(...) — ин «дидан, ки одам ба кадом аудитория равона шудааст» аст.
Хатои маъмул
event.target-ро бе closest истифода бурдан. Агар дар дохили тугма нишона ё <span> бошад, target маҳз он мешавад, на тугма, ва санҷиш кор намекунад. closest("button") дар дарахт ба боло то элементи лозимӣ мебарояд.
Барои муфассалтар хондан: learn.javascript.ru — делегирование событий · learn.javascript.ru — событие submit
Амалиёт: мустаҳкам мекунем
ВАЗИФАИ 7.1 Ҳисобкунаки пахшҳо осон
Ба тугма коркардкунандаи click овезед: он clicks-ро зиёд мекунад ва ба тугма матни Нажато: N-ро менависад. Се даъвати btn.click() аллакай ҳаст — онҳо пахшҳоро тақлид мекунанд.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const btn = document.createElement ("button" );
let clicks = 0 ;
// коркардкунандаи click-ро овезед
btn.click ();
btn.click ();
btn.click ();
console.log (clicks);
console.log (btn.textContent);
Натиҷаи интизоршаванда 3
Нажато: 3
Ишора 1 Схема: btn.addEventListener("click", () => { ... }); — дар дохил clicks-ро зиёд кунед.
Ишора 2 Матни тугма тавассути btn.textContent = "Нажато: " + clicks; тағйир меёбад — дар ҳамон коркардкунанда.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 7.2 Шакл бо санҷиш миёна
Коркардкунандаи submit-ро нависед: он ирсолро бекор мекунад (preventDefault), қимати майдонро бе фосилаҳои канорӣ мегирад, сатри холиро нодида мегирад, ва ғайрихолиро ба массиви tasks мегузорад ва майдонро пок мекунад.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const form = document.createElement ("form" );
form.innerHTML = '<input name="title"><button>Добавить</button>' ;
const input = form.querySelector ("input" );
const tasks = [];
// коркардкунандаи submit-ро ба form овезед
function submit (value) {
input.value = value;
const notCancelled = form.dispatchEvent (new Event ("submit" , { cancelable: true }));
console.log ("отправка отменена:" , !notCancelled);
}
submit ("Купить лепёшки" );
submit (" " );
submit ("Сделать ДЗ" );
console.log (tasks.join (" | " ));
console.log (JSON.stringify (input.value));
Натиҷаи интизоршаванда отправка отменена: true
отправка отменена: true
отправка отменена: true
Купить лепёшки | Сделать ДЗ
""
Ишора 1 Сатри аввали коркардкунанда — event.preventDefault(): он бояд ҳангоми ҳар қимати майдон иҷро шавад, вагарна саҳифа «аз нав бор мешавад».
Ишора 2 const title = input.value.trim(); if (!title) return; — баъд tasks.push(title) ва input.value = "".
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 7.3 Нест кардан тавассути вакилкунӣ миёна
Як коркардкунандаро ба list овезед. Агар клик ба тугма бо data-action="delete" омад, id-и вазифаро ба массиви removed нависед ва элементи <li>-ро нест кунед. Клик ба худи матн чизе намекунад.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const list = document.createElement ("ul" );
list.innerHTML = `
<li data-id="1">Плов <button data-action="delete">✕</button></li>
<li data-id="2">Чой <button data-action="delete">✕</button></li>
<li data-id="3">Самбуса <button data-action="delete">✕</button></li>` ;
const removed = [];
// як коркардкунандаи click дар list
list.querySelectorAll ("button" )[1 ].click (); // «Чой»-ро нест мекунем
list.querySelector ("button" ).click (); // «Плов»-ро нест мекунем
list.querySelector ("li" ).click (); // клик ба матн — чизе рӯй намедиҳад
console.log (removed.join ("," ));
console.log (list.children.length);
console.log (list.firstElementChild.dataset.id);
Натиҷаи интизоршаванда 2,1
1
3
Ишора 1 Дар дохили коркардкунанда: const btn = event.target.closest("button[data-action='delete']"); ва if (!btn) return;.
Ишора 2 Вазифаро чунин ёбед: const li = btn.closest("li"); — он li.dataset.id дорад. Нест кардани элемент — li.remove().
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 7.4 Трекери хурд пурра душвор
Ядрои зиндаи трекерро ҷамъ кунед. Функсияҳои ҳолат ва createTaskItem аллакай тайёранд. Ба итмом расонед:
render() — рӯйхатро пок мекунад ва аз state.tasks месозад;
коркардкунандаи submit-и шакл — вазифа илова мекунад (холиро нодида мегирад), майдонро пок мекунад, render-ро даъват мекунад;
як коркардкунандаи click дар рӯйхат: клик ба «✕» вазифаро нест мекунад, клик ба ҳар ҷойи дигари вазифа — done-ро иваз мекунад. Нест кардан набояд боз иваз ҳам кунад!
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const root = document.createElement ("div" );
root.innerHTML = `
<form><input><button>Добавить</button></form>
<ul></ul>` ;
const form = root.querySelector ("form" );
const input = root.querySelector ("input" );
const list = root.querySelector ("ul" );
let state = { tasks: [], nextId: 1 };
const addTask = (s, title) => ({
tasks: [... s.tasks, { id: s.nextId, title, done: false }],
nextId: s.nextId + 1 ,
});
const toggleTask = (s, id) => ({
... s,
tasks: s.tasks.map ((t) => (t.id === id ? { ... t, done: !t.done } : t)),
});
const removeTask = (s, id) => ({ ... s, tasks: s.tasks.filter ((t) => t.id !== id) });
function createTaskItem (task) {
const li = document.createElement ("li" );
li.dataset.id = task.id;
if (task.done) li.classList.add ("done" );
const span = document.createElement ("span" );
span.textContent = task.title;
const del = document.createElement ("button" );
del.dataset.action = "delete" ;
del.textContent = "✕" ;
li.append (span, del);
return li;
}
// 1) function render() { ... }
// 2) form.addEventListener("submit", ...)
// 3) list.addEventListener("click", ...)
// --- санҷиш: амалҳои корбарро тақлид мекунем ---
const add = (text) => {
input.value = text;
form.dispatchEvent (new Event ("submit" , { cancelable: true }));
};
add ("Плов" );
add ("Чой" );
add ("Самбуса" );
console.log (list.children.length);
list.children[1 ].querySelector ("span" ).click (); // «Чой»-ро қайд кардем
list.children[0 ].querySelector ("button" ).click (); // «Плов»-ро нест кардем
const summary = [... list.children]
.map ((li) => li.querySelector ("span" ).textContent + (li.classList.contains ("done" ) ? " ✓" : "" ))
.join (" | " );
console.log (list.children.length);
console.log (summary);
Натиҷаи интизоршаванда 3
2
Чой ✓ | Самбуса
Ишора 1 Қолаби умумии ҳар амал: state-ро тағйир додем → render()-ро даъват кардем . Дар submit: state = addTask(state, title); render();.
Ишора 2 Дар коркардкунандаи клик: const li = event.target.closest("li"); if (!li) return;, id — ин Number(li.dataset.id) аст. Аввал санҷед, ки клик ба button[data-action='delete'] буд — он гоҳ removeTask. Вагарна — toggleTask.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
08 Гармкунии 4. Филтрҳо, ҳисобкунакҳо ва силсилаҳо
Филтр нест кардани вазифаҳо нест, балки назари дигар ба ҳамон ҳолат аст. Мо ҳамаи вазифаҳоро ва реҷаи интихобшудаи state.filter-ро нигоҳ медорем, ва render танҳо мувофиқҳоро нишон медиҳад. Бинобар ин иваз кардани филтр ҳеҷ гоҳ чизеро гум намекунад.
Филтр ҳамчун функсияи ҳолат · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const tasks = [
{ title: "Плов" , done: true },
{ title: "Чой" , done: false },
];
function getVisible (tasks, filter) {
if (filter === "active" ) return tasks.filter ((t) => !t.done);
if (filter === "done" ) return tasks.filter ((t) => t.done);
return tasks; // "all" ва ҳама дигар
}
console.log (getVisible (tasks, "active" ).length);
console.log (tasks.length); // массиви аслӣ зарар надид
Ҳисобкунакҳо аз ҳолат ҳисоб мешаванд, нигоҳ дошта намешаванд
Адади «Осталось: 3 из 5»-ро бо майдони алоҳида нигоҳ доштан ва ҳангоми ҳар амал бо даст нав кардан лозим нест. Онро ҳамеша аз массив ҳисоб кардан мумкин аст. Агар ду бор нигоҳ доранд, дер ё зуд қиматҳо ихтилоф мекунанд.
Барои варианти Б: одатҳо ва силсилаҳо
Одат «ба таври абадӣ иҷро шуда» надорад: он ҳар рӯз иҷро мешавад. Бинобар ин ба ҷои done массиви санаҳои days: ["2026-10-14", "2026-10-15"]-ро нигоҳ медорем. «Имрӯз анҷом шуд» — ин санҷиши days.includes(today) аст, ва силсила — чанд рӯз пай дар пай қайдҳо мераванд.
Муҳим: «санаи имрӯза»-ро дар дохили мантиқ даъват накунед
Натиҷаи функсияе, ки худаш «имрӯз»-ро мефаҳмад, ҳар рӯз тағйир меёбад, ва санҷидани он ғайриимкон аст. Бинобар ин функсияи streak(dates, today) «имрӯз»-ро ҳамчун аргумент мегирад. Дар барнома шумо санаи воқеиро медиҳед, ва ҳангоми санҷиш — ҳар як хаёлиро. Ин усули умумӣ аст: функсияҳои тозаро санҷидан осон аст.
Барои муфассалтар хондан: learn.javascript.ru — методы массивов (filter, find, includes)
Амалиёт: мустаҳкам мекунем
ВАЗИФАИ 8.1 Се реҷаи рӯйхат осон
getVisible(tasks, filter)-ро нависед: барои "all" ҳамаи вазифаҳоро, барои "active" — иҷронашудаҳоро, барои "done" — иҷрошудаҳоро бармегардонад.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const tasks = [
{ title: "Плов" , done: true },
{ title: "Чой" , done: false },
{ title: "Самбуса" , done: true },
{ title: "Курутоб" , done: false },
];
// function getVisible(tasks, filter) { ... }
for (const f of ["all" , "active" , "done" ]) {
console.log (f + ":" , getVisible (tasks, f).map ((t) => t.title).join (", " ));
}
Натиҷаи интизоршаванда all: Плов, Чой, Самбуса, Курутоб
active: Чой, Курутоб
done: Плов, Самбуса
Ишора 1 Ду шарт бо return-и барвақт (барои "active" ва "done"), ва дар охир — return tasks.
Ишора 2 Иҷронашудаҳо: tasks.filter(t => !t.done), иҷрошудаҳо: tasks.filter(t => t.done).
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 8.2 Матни ҳисобкунак миёна
counterText(tasks)-ро нависед. Агар вазифаҳо набошанд — Задач пока нет. Агар ҳама иҷро шуда бошанд — Всё сделано!. Вагарна — Осталось: N из M, ки N — иҷронашудаҳо, M — ҳама.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
// function counterText(tasks) { ... }
console.log (counterText ([]));
console.log (counterText ([{ done: true }, { done: false }, { done: false }, { done: true }]));
console.log (counterText ([{ done: true }, { done: true }]));
Натиҷаи интизоршаванда Задач пока нет
Осталось: 2 из 4
Всё сделано!
Ишора 1 Ҳолатҳои махсусро пеш аз оддӣ санҷед: аввал массиви холӣ, баъд «ҳама иҷро шудаанд», дар охир — сатри оддӣ.
Ишора 2 Шумораи иҷронашудаҳо: tasks.filter(t => !t.done).length. Сатр: `Осталось: ${left} из ${tasks.length}`.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 8.3 Тугмаҳои филтрҳо миёна
Як коркардкунандаи click-ро ба контейнери box овезед. Клик ба тугма бо data-filter қиматро ба state.filter менависад ва синфи active-ро ба тугмаи пахшшуда мегузаронад (дар боқимонда нест мешавад).
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const state = { filter: "all" };
const box = document.createElement ("div" );
box.innerHTML = `
<button data-filter="all" class="active">Все</button>
<button data-filter="active">Активные</button>
<button data-filter="done">Готовые</button>` ;
// як коркардкунандаи click дар box
const report = () => {
const act = [... box.querySelectorAll (".active" )].map ((b) => b.textContent);
console.log (state.filter, act.join ("," ));
};
report ();
box.querySelector ("[data-filter='done']" ).click ();
report ();
box.querySelector ("[data-filter='active']" ).click ();
report ();
Натиҷаи интизоршаванда all Все
done Готовые
active Активные
Ишора 1 Тугмаро ёбед: event.target.closest("button[data-filter]"), ҳангоми null — бароед. Қимати филтр дар btn.dataset.filter аст.
Ишора 2 Аз болои ҳамаи тугмаҳо гузаред ва барои ҳар кадом b.classList.toggle("active", b === btn)-ро даъват кунед — аргументи дуюм синфро фаъол ё хомӯш мекунад.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 8.4 Силсилаи рӯзҳои пай дар пай (барои одатҳо) душвор
streak(dates, today)-ро нависед — чанд рӯз пай дар пай одат қайд шудааст. Қоидаҳо: агар имрӯз қайд шуда бошад — аз имрӯз ба қафо ҳисоб мекунем; агар имрӯз ҳанӯз не, аммо дирӯз буд — силсила қатъ нашудааст, аз дирӯз ҳисоб мекунем; агар на имрӯз ва на дирӯз бошад — силсила 0. Такрори санаҳо ба натиҷа таъсир намерасонад. Функсияи prevDay аллакай тайёр аст: он рӯзи гузаштаро бармегардонад.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const prevDay = (str) => {
const d = new Date (str + "T00:00:00Z" );
d.setUTCDate (d.getUTCDate () - 1 );
return d.toISOString ().slice (0 , 10 );
};
// function streak(dates, today) { ... }
const today = "2026-10-15" ;
console.log (streak (["2026-10-12" , "2026-10-13" , "2026-10-14" , "2026-10-15" ], today));
console.log (streak (["2026-10-10" , "2026-10-13" , "2026-10-14" ], today));
console.log (streak (["2026-10-01" , "2026-10-02" ], today));
console.log (streak ([], today));
console.log (streak (["2026-10-15" , "2026-10-14" , "2026-10-14" , "2026-10-11" ], today));
Натиҷаи интизоршаванда 4
2
0
0
2
Ишора 1 Рӯзи оғозиро интихоб кунед: today, агар он дар dates бошад, вагарна prevDay(today). Баъд ба қафо равед, то даме ки сана дар массив ҳаст.
Ишора 2 Давраи while (dates.includes(day)) { count++; day = prevDay(day); }. Агар рӯзи оғозӣ ёфт нашавад, давра фавран меистад ва 0 бармегардад.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
09 Гармкунии 5. Захира: localStorage ва JSON
Хишти охирини MVP — то маълумот баъди бастани ҷадвал гум нашавад . localStorage — ин анбори хурд бевосита дар браузер аст: ҷуфтҳои «калид — қимат». Се усул, ки қариб ҳамеша лозиманд: setItem(key, value), getItem(key) ва removeItem(key).
Маҳдудияти асосӣ: танҳо сатрҳо нигоҳ дошта мешаванд . Адад ба сатри "10" табдил меёбад, ва объект ба "[object Object]"-и бефоида. Бинобар ин ҳолатро пеш аз навиштан ба сатри JSON табдил медиҳем (JSON.stringify), ва баъди хондан — боз ба объект (JSON.parse).
Эзоҳ дар бораи қуттии санҷиши ин саҳифа
Коди ин саҳифа дар «қуттии санҷиш»-и ҷудогонаи браузер иҷро мешавад — ин ҳимоя аст, то коди бегона ба маълумоти шумо нарасад. Дар он localStorage-и воқеӣ банд аст . Бинобар ин дар машқҳо мо ивазкунак -ро истифода мебарем — объекти storage бо ҳамон API (getItem, setItem, removeItem), ки маълумотро дар хотира нигоҳ медорад. Мантиқи код дар ин ҳол як ва ҳамон аст. Дар лоиҳаи худи шумо дар VS Code тамоми блокро бо як сатр иваз мекунед: const storage = localStorage;.
Қуттии санҷишро месанҷем: оё localStorage дастрас аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
try {
localStorage.setItem ("test" , "1" );
console.log ("localStorage работает" );
} catch (error) {
console.log ("localStorage недоступен:" , error.name);
}
Одатан шумо SecurityError-ро мебинед. Ин муқаррарӣ аст: маҳз бинобар ин мо дар зер тавассути ивазкунак кор мекунем. Онро нусха кунед — он дар ҳар машқи ин бахш лозим аст:
Ивазкунаки localStorage бо ҳамон API · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const storage = {
data: {},
getItem (key) { return key in this .data ? this .data[key] : null ; },
setItem (key, value) { this .data[key] = String (value); }, // мисли воқеӣ: ҳама чиз ба сатр
removeItem (key) { delete this .data[key]; },
};
storage.setItem ("score" , 10 );
console.log (typeof storage.getItem ("score" )); // string, на number
console.log (storage.getItem ("нет такого" )); // null — калид нест
const state = { tasks: [{ id: 1 , title: "Плов" , done: false }], nextId: 2 };
storage.setItem ("tracker:v1" , JSON.stringify (state)); // объект → сатр
console.log (storage.getItem ("tracker:v1" ));
const back = JSON.parse (storage.getItem ("tracker:v1" )); // сатр → объект
console.log (back.tasks[0 ].title);
Муқоиса аз ҳаёт
Ҳангоми фиристодани бастаи аз Душанбе ба Хуҷанд шумо ҷевонро пурра намебаред: ҷудо мекунед, ба қуттиҳо мепечонед (JSON.stringify), ва гиранда боз ҷамъ мекунад (JSON.parse). Анбор танҳо «қуттиҳо»-ро мефаҳмад — яъне сатрҳоро.
Маълумотро бехатар мехонем
Маълумот дар localStorage метавонад вайрон шуда бошад, онро корбар метавонист дастӣ ислоҳ кунад, ва ҳангоми оғози аввал он танҳо нест. Агар бешубҳа JSON.parse-ро даъват кунед, барнома ҳанӯз пеш аз кадри аввал меафтад. Бинобар ин чунин мехонем: try/catch + санҷиши шакл + варианти эҳтиётӣ .
Боркунии бехатари ҳолат · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const storage = { data: {}, getItem (k) { return k in this .data ? this .data[k] : null ; }, setItem (k, v) { this .data[k] = String (v); } };
const KEY = "tracker:v1" ;
function loadState () {
try {
const state = JSON.parse (storage.getItem (KEY)); // null ё JSON-и шикаста
if (state && Array.isArray (state.tasks)) return state; // шаклро месанҷем
} catch {
// JSON-и шикаста — тарсе нест, аз варақи тоза оғоз мекунем
}
return { tasks: [], filter: "all" , nextId: 1 };
}
console.log (loadState ().tasks.length); // 0 — маълумот ҳанӯз нест
storage.setItem (KEY, "{oops" );
console.log (loadState ().tasks.length); // 0 — JSON шикаста, барнома зинда
Хатоҳои маъмул
1. JSON.stringify-ро фаромӯш кардан ва объектро бевосита навиштан — "[object Object]" мегиред. 2. Фаромӯш кардан, ки getItem сатр бармегардонад: "10" + 5 "105" медиҳад. 3. Калиди умумиро мисли "data" истифода бурдан: лоиҳаи бегона дар ҳамон сайт маълумоти шуморо аз нав менависад. Калидро бо префикс гиред: "tracker:v1" (ва v1 лозим мешавад, агар рӯзе формат тағйир ёбад).
Барои муфассалтар хондан: learn.javascript.ru — localStorage, sessionStorage · learn.javascript.ru — JSON · MDN — localStorage
Амалиёт: мустаҳкам мекунем
ВАЗИФАИ 9.1 Адад сатр шуд осон
Холи бозии 10 ба анбор навишта шуд, хонда шуд ва мехоҳем 5 илова кунем. Интизор 15, аммо чизи аҷибе мегирем. Кодро ислоҳ кунед.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const storage = {
data: {},
getItem (key) { return key in this .data ? this .data[key] : null ; },
setItem (key, value) { this .data[key] = String (value); },
removeItem (key) { delete this .data[key]; },
};
storage.setItem ("score" , 10 );
const score = storage.getItem ("score" );
console.log (score + 5 ); // мехоҳем 15
Ишора 1 Онро чун ҳаст иҷро кунед ва ба натиҷа нигоҳ кунед. + чӣ мекунад, агар дар як тараф сатр бошад?
Ишора 2 Қимати хондашударо ба адад табдил диҳед: Number(storage.getItem("score")).
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 9.2 Захира ва хондани ҳолат миёна
saveState(state) (JSON-ро ба storage таҳти калиди KEY менависад) ва loadState() (мехонад ва ба объект бармегардонад)-ро нависед.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const storage = {
data: {},
getItem (key) { return key in this .data ? this .data[key] : null ; },
setItem (key, value) { this .data[key] = String (value); },
removeItem (key) { delete this .data[key]; },
};
const KEY = "tracker:v1" ;
// const saveState = (state) => ...
// const loadState = () => ...
saveState ({
tasks: [{ id: 1 , title: "Плов" , done: false }, { id: 2 , title: "Чой" , done: true }],
filter: "all" ,
nextId: 3 ,
});
console.log (typeof storage.getItem (KEY));
const loaded = loadState ();
console.log (loaded.tasks.length);
console.log (loaded.tasks[1 ].title, loaded.tasks[1 ].done);
console.log (loaded.nextId);
Натиҷаи интизоршаванда string
2
Чой true
3
Ишора 1 Навиштан: storage.setItem(KEY, JSON.stringify(state)). Хондан: JSON.parse(storage.getItem(KEY)).
Ишора 2 Ҳар ду функсия — якто сатр. Худро санҷед: typeof-и қимати хондашуда бояд "string" бошад, ва loaded.tasks — массиви воқеӣ.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 9.3 Маълумоти шикаста набояд барномаро вайрон кунад миёна
Ҳоло loadState бо хато меафтад, агар маълумот набошад, шикаста бошад ё шакли нодуруст дошта бошад. Онро аз нав нависед: try/catch, санҷиши Array.isArray(state.tasks) ва ҳолати холии эҳтиётӣ.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const storage = {
data: {},
getItem (key) { return key in this .data ? this .data[key] : null ; },
setItem (key, value) { this .data[key] = String (value); },
removeItem (key) { delete this .data[key]; },
};
const KEY = "tracker:v1" ;
function loadState () {
return JSON.parse (storage.getItem (KEY));
}
console.log ("пусто:" , loadState ().tasks.length);
storage.setItem (KEY, "{oops, не JSON" );
console.log ("сломано:" , loadState ().tasks.length);
storage.setItem (KEY, JSON.stringify ({ tasks: [{ id: 1 }, { id: 2 }], filter: "all" , nextId: 3 }));
console.log ("нормально:" , loadState ().tasks.length);
storage.setItem (KEY, JSON.stringify ({ tasks: "oops" }));
console.log ("странно:" , loadState ().tasks.length);
Натиҷаи интизоршаванда пусто: 0
сломано: 0
нормально: 2
странно: 0
Ишора 1 JSON.parse-ро дар try { ... } catch { ... } бипечонед. Дар дохили try баъди таҳлил шаклро санҷед ва ҳолатро баргардонед.
Ишора 2 Шарти шакл: state && Array.isArray(state.tasks) (барои null ва барои "oops" он нодуруст аст). Агар санҷиш нагузашт ё хато шуд — баъди блоки try/catch return { tasks: [], filter: "all", nextId: 1 }.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 9.4 «Аз нав бор кардани саҳифа» душвор
load() ва save(state)-ро чунон ба итмом расонед, ки баъди «аз нав бор кардан» (boot()) ҳама чиз барқарор шавад: вазифаҳо, қайдҳо ва рақами навбатӣ. Функсияи load бояд маълумоти нодурустро ҳам тоб орад: tasks — массив ва nextId — адад лозиманд, вагарна fresh()-ро бармегардонем.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const storage = {
data: {},
getItem (key) { return key in this .data ? this .data[key] : null ; },
setItem (key, value) { this .data[key] = String (value); },
removeItem (key) { delete this .data[key]; },
};
const KEY = "tracker:v1" ;
const fresh = () => ({ tasks: [], nextId: 1 });
const add = (s, title) => ({
tasks: [... s.tasks, { id: s.nextId, title, done: false }],
nextId: s.nextId + 1 ,
});
const toggle = (s, id) => ({
... s,
tasks: s.tasks.map ((t) => (t.id === id ? { ... t, done: !t.done } : t)),
});
// function load() { ... }
// function save(state) { ... }
const boot = () => load (); // барнома баъди F5 ҳамин тавр оғоз мешавад
let s = boot ();
s = add (s, "Плов" ); save (s);
s = add (s, "Чой" ); save (s);
s = boot (); // «саҳифаро аз нав бор кард»
console.log (s.tasks.length, s.nextId);
s = add (s, "Самбуса" ); save (s);
s = boot ();
console.log (s.tasks.map ((t) => t.id + ":" + t.title).join (" " ));
s = toggle (s, 2 ); save (s);
s = boot ();
console.log (s.tasks.filter ((t) => t.done).map ((t) => t.title).join ());
storage.setItem (KEY, '{"tasks": "oops"}' ); // маълумотро вайрон кард
console.log (boot ().tasks.length);
Натиҷаи интизоршаванда 2 3
1:Плов 2:Чой 3:Самбуса
Чой
0
Ишора 1 save — як сатр бо JSON.stringify. Дар load усули вазифаи гузаштаро такрор кунед: try/catch ва санҷиши шакл.
Ишора 2 Санҷиши шакл: data && Array.isArray(data.tasks) && typeof data.nextId === "number". Агар гузашт — data-ро баргардонед, вагарна (ва ҳангоми хато) — fresh().
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
10 Қолаби оғозии лоиҳа
Дар зер — скелети кории трекери вазифаҳо . Он аллакай вазифаҳоро илова карда ва кашида метавонад, ва боқӣ — «TODO»-и шумо. Код ба шаш блок ҷудо шудааст бо тартибе, ки хондан ва шарҳ додан дар ҳимоя қулай аст: анбор → ҳолат → элементҳои саҳифа → кашидан → нуқтаи ягонаи тағйирот → ҳодисаҳо .
Анбор. Дар қуттии санҷиш — ивазкунак, дар лоиҳа — localStorage-и воқеӣ.
Ҳолат ва функсияҳо болои он. Функсияҳои тоза: ҳолат гирифтем — навро баргардонидем.
Элементҳои саҳифа. Як маротиба ҳама чизи лозимро тавассути querySelector меёбем.
Кашидан. render() интерфейсро аз state месозад. Дигар касе DOM-ро намерасонад.
Нуқтаи ягонаи тағйирот. commit(next): ҳолати навро навиштан, захира кардан, аз нав кашидан. Ҳар амали корбар бо он анҷом меёбад.
Ҳодисаҳо. Шакл, рӯйхат (вакилкунӣ), филтрҳо.
▶ Запустить -ро пахш кунед, якчанд вазифа илова кунед — ва мебинед, ки қайд, нест кардан ва филтрҳо ҳоло кор намекунанд. Ин вазифа барои шумост.
Амалиёт: трекери оғозиро ба итмом мерасонем
ВАЗИФАИ 10.1 TODO-ро ба итмом расонед — ва трекер кор мекунад душвор
Дар script.js панҷ нишонаи TODO-ро ёбед ва онҳоро амалӣ кунед: 1) toggleTask, 2) removeTask, 3) getVisible, 4) load ва save (бо ҳимоя аз маълумоти шикаста), 5) коркардкунандаи тугмаҳои филтр. Дар поёни файл — блоки худсанҷӣ: он худаш ба интерфейс «клик мекунад» ва натиҷаро ба консол чоп мекунад. Вақте ҳама чиз тайёр аст, дар он бояд айнан ҳамон бошад, ки дар блоки «Натиҷаи интизоршаванда». Блоки худсанҷиро ба лоиҳаи худ нусха накунед.
Трекери оғозии вазифаҳо · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
index.html style.css script.js
< main class ="app" >
< h1 > Трекер задач</ h1 >
< form id ="form" >
< input id ="title" placeholder ="Что нужно сделать?" autocomplete ="off" >
< button > Добавить</ button >
</ form >
< div class ="filters" id ="filters" >
< button data-filter ="all" > Все</ button >
< button data-filter ="active" > Активные</ button >
< button data-filter ="done" > Готовые</ button >
</ div >
< ul id ="list" > </ ul >
< p id ="counter" > </ p >
</ main >
.app { max-width : 420px ; margin : 0 auto; }
h1 { font-size : 22px ; margin : 0 0 12px ; }
form { display : flex; gap : 8px ; }
input { flex : 1 ; padding : 8px 10px ; border : 1px solid #c7ccd6 ; border-radius : 8px ; font : inherit; }
button { padding : 8px 12px ; border : 0 ; border-radius : 8px ; background : #1f6feb ; color : #fff ; font : inherit; cursor : pointer; }
.filters { display : flex; gap : 6px ; margin : 12px 0 ; }
.filters button { background : #eef1f6 ; color : #1c2230 ; }
.filters button.active { background : #1c2230 ; color : #fff ; }
ul { list-style : none; padding : 0 ; margin : 0 ; }
li { display : flex; justify-content : space-between; align-items : center; padding : 8px 4px ; border-bottom : 1px solid #e6e9f0 ; cursor : pointer; }
li.done span { text-decoration : line-through; color : #8a93a6 ; }
li.empty { justify-content : center; color : #8a93a6 ; cursor : default; }
li button { background : transparent; color : #d1344f ; padding : 2px 8px ; }
#counter { color : #5b6477 ; font-size : 14px ; }
// ===== 1. Анбор =====
// localStorage-и воқеӣ дар қуттии санҷиш банд аст, бинобар ин ивазкунакро бо ҳамон API мегирем.
// Дар лоиҳаи худатон тамоми ин блок бо як сатр иваз мешавад: const storage = localStorage;
const storage = {
data: {},
getItem (key) { return key in this .data ? this .data[key] : null ; },
setItem (key, value) { this .data[key] = String (value); },
removeItem (key) { delete this .data[key]; },
};
const KEY = "tracker:v1" ;
// ===== 2. Ҳолат ва функсияҳо болои он (ҳар кадом ҳолати НАВ-ро бармегардонад) =====
const createState = () => ({ tasks: [], filter: "all" , nextId: 1 });
function addTask (state, title) {
const clean = title.trim ();
if (!clean) return state;
return {
... state,
tasks: [... state.tasks, { id: state.nextId, title: clean, done: false }],
nextId: state.nextId + 1 ,
};
}
// TODO 1: done-ро дар вазифа бо id-и лозимӣ баръакс кунед
function toggleTask (state, id) {
return state;
}
// TODO 2: вазифаро бо id-и лозимӣ бардоред
function removeTask (state, id) {
return state;
}
// TODO 3: вазифаҳоро мувофиқи state.filter баргардонед ("all" | "active" | "done")
function getVisible (state) {
return state.tasks;
}
function counterText (tasks) {
if (tasks.length === 0 ) return "Задач пока нет" ;
const left = tasks.filter ((t) => !t.done).length;
if (left === 0 ) return "Всё сделано!" ;
return `Осталось: ${left} из ${tasks.length}` ;
}
// TODO 4: ҳолатро аз storage хонед. Холӣ ё шикаста — createState()-ро баргардонед
function load () {
return createState ();
}
// TODO 4: ҳолатро ба storage захира кунед
function save (state) {
}
// ===== 3. Элементҳои саҳифа =====
const form = document.querySelector ("#form" );
const titleInput = document.querySelector ("#title" );
const filters = document.querySelector ("#filters" );
const list = document.querySelector ("#list" );
const counter = document.querySelector ("#counter" );
// ===== 4. Кашидан: интерфейс пурра аз state сохта мешавад =====
function createTaskItem (task) {
const li = document.createElement ("li" );
li.dataset.id = task.id;
if (task.done) li.classList.add ("done" );
const span = document.createElement ("span" );
span.textContent = task.title;
const del = document.createElement ("button" );
del.dataset.action = "delete" ;
del.textContent = "✕" ;
li.append (span, del);
return li;
}
function render () {
const visible = getVisible (state);
list.innerHTML = "" ;
if (visible.length === 0 ) {
const empty = document.createElement ("li" );
empty.className = "empty" ;
empty.textContent = "Здесь пока пусто" ;
list.append (empty);
}
visible.forEach ((task) => list.append (createTaskItem (task)));
filters.querySelectorAll ("button" ).forEach ((b) => {
b.classList.toggle ("active" , b.dataset.filter === state.filter);
});
counter.textContent = counterText (state.tasks);
}
// ===== 5. Нуқтаи ягонаи тағйирот =====
let state = load ();
function commit (next) {
state = next;
save (state);
render ();
}
// ===== 6. Ҳодисаҳо =====
form.addEventListener ("submit" , (event) => {
event.preventDefault ();
commit (addTask (state, titleInput.value));
titleInput.value = "" ;
titleInput.focus ();
});
list.addEventListener ("click" , (event) => {
const li = event.target.closest ("li[data-id]" );
if (!li) return ;
const id = Number (li.dataset.id);
if (event.target.closest ("button[data-action='delete']" )) commit (removeTask (state, id));
else commit (toggleTask (state, id));
});
// TODO 5: коркардкунандаи click дар filters. Тугма бо data-filter → commit({ ...state, filter: ... })
render ();
// ===== Худсанҷӣ барои вазифаи 10.1 (ба лоиҳаи худ нусха накунед) =====
{
const add = (text) => {
titleInput.value = text;
form.dispatchEvent (new Event ("submit" , { cancelable: true }));
};
add ("Плов" );
add ("Чой" );
add ("Самбуса" );
console.log ("добавление:" , list.children.length);
list.children[1 ].querySelector ("span" ).click ();
console.log ("отметка:" , list.querySelectorAll ("li.done" ).length);
list.children[0 ].querySelector ("button" ).click ();
console.log ("удаление:" , list.children.length);
filters.querySelector ("[data-filter='done']" ).click ();
console.log ("фильтр:" , list.children.length);
console.log ("хранилище:" , (JSON.parse (storage.getItem (KEY) || "{}" ).tasks || []).length);
commit (createState ()); // аз паси худ тоза мекунем
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда добавление: 3
отметка: 1
удаление: 2
фильтр: 1
хранилище: 2
Ишора 1 Қолабро чун ҳаст иҷро кунед: дар консол отметка: 0, удаление: 3 ва ғайра хоҳад буд — ин рӯйхати он аст, ки чиро ба итмом расондан лозим. Ҳар TODO-ро алоҳида ҳал кунед ва баъди ҳар кадом иҷро кунед.
Ишора 2 toggleTask ва removeTask — ҳамон функсияҳое, ки шумо дар гармкунӣ навиштед (map бо нусхаи вазифа ва filter). getVisible ба state.filter нигоҳ мекунад. load: try/catch + Array.isArray. Филтрҳо: event.target.closest("button[data-filter]"), баъд commit({ ...state, filter: btn.dataset.filter }).
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
Қолабро ба лоиҳаи худ чӣ тавр интиқол додан
Дар VS Code папкаи лоиҳа ва се файл созед: index.html, style.css, script.js. Аломатгузориро аз ҷадвали index.html ба дохили <body> гузоред, ҷадвалҳои боқимонда — ба файлҳои ҳамном.
Дар index.html услубҳо ва скриптро пайваст кунед: <link rel="stylesheet" href="style.css"> ва дар охири body — <script src="script.js"></script>.
Блоки «Анбор»-ро бо як сатр иваз кунед: const storage = localStorage;.
Блоки худсанҷиро дар поёни файл нест кунед.
Агар шумо аллакай лоиҳа аз дарсҳои 9–11 дошта бошед — онро напартоед. Сохтори онро бо қолаб муқоиса кунед ва аз рӯи нақшаи «ҳолат → render → commit → ҳодисаҳо» аз нав созед.
Варианти Б: дар қолаб барои одатҳо чӣ тағйир меёбад
Қисм Вазифаҳо Одатҳо Ниҳод { id, title, done }{ id, name, days: [] }Массив дар ҳолат taskshabitsҚайд toggleTask(state, id)toggleToday(state, id, today)«Иҷро шуд?» task.donehabit.days.includes(today)Иловатан — streak(days, today) аз вазифаи 8.4Ҳисобкунак Осталось: N из M Сегодня: N из M
Қайди одат барои имрӯз (варианти Б) · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const toggleToday = (state, id, today) => ({
... state,
habits: state.habits.map ((h) => {
if (h.id !== id) return h;
const days = h.days.includes (today)
? h.days.filter ((d) => d !== today) // қайд аллакай буд — мебардорем
: [... h.days, today]; // қайд набуд — мегузорем
return { ... h, days };
}),
});
const state = { habits: [{ id: 1 , name: "Читать 20 минут" , days: ["2026-10-14" ] }] };
const today = "2026-10-15" ; // дар барнома: new Date().toISOString().slice(0, 10)
const s1 = toggleToday (state, 1 , today);
console.log (s1.habits[0 ].days.join (", " ));
const s2 = toggleToday (s1, 1 , today);
console.log (s2.habits[0 ].days.join (", " ));
Қайд: toISOString() санаро аз рӯи UTC ҳисоб мекунад. Барои лоиҳаи таълимӣ ин иҷозат аст, аммо наздики нисфишаб «имрӯз» метавонад аз рӯзи маҳаллии шумо ба якчанд соат фарқ кунад. Инро дар ҳимоя ҳамчун маҳдудияти маълум зикр кардан мумкин аст.
11 Амалиёт дар дарс: 90 дақиқа
Дар машғулот шумо лоиҳаро то MVP мерасонед , якдигарро месанҷед ва ҳимояҳоро оғоз мекунед. Вақт маҳдуд аст, бинобар ин аз рӯи нақша амал мекунем.
0–10 дақ · Декомпозитсия. Шумо вариантро (А ё Б) интихоб кардед, бо ЗС нақшаи 10–15 қадамро тартиб додед ва онро аз рӯи қоидаҳои бахши 04 ислоҳ кардед. Нақшаро ба ҳамсоя нишон диҳед: 1 дақиқа барои саволи «қадами аз ҳама хатарнок дар ту кадом аст?». Омӯзгор вариантҳо ва нақшаҳоро тасдиқ мекунад.
10–50 дақ · Такмили лоиҳа. Бо нақшаи худ аз боло ба поён мегузаред. Қоидаи понздаҳ дақиқа: ҳар 15 дақиқа — истед, F5, санҷиш дар браузер ва дар консол. Монда шудед — аввал худатон 15 дақиқа, баъд ҳамсоя, баъд ЗС, баъд омӯзгор.
50–70 дақ · Code review дар ҷуфт. Барои ҳар лоиҳа 10 дақиқа. Баррасикунанда аз рӯи чек-листи бахши 12 мегузарад, муаллиф гӯш мекунад ва менависад. Баъд ҷой иваз мекунед.
70–90 дақ · Ислоҳот ва оғози ҳимояҳо. Эродҳои ревьюро ислоҳ мекунед. Ҳимояҳо ба навбат мегузаранд (5 дақиқа + як дақиқа барои иваз), тартибро омӯзгор муайян мекунад. Он ки имрӯз муваффақ нашуд — дар оғози машғулоти оянда ё бо мувофиқа ҳимоя мекунад.
Нуқтаҳои назоратӣ: шумо бояд дар куҷо бошед
Вақт Бояд кор кунад баъди 20 дақ аломатгузорӣ, ҳолат, render: вазифаҳо аз массив дар саҳифа намоёнанд баъди 30 дақ шакл илова мекунад, клик ба вазифа қайд мекунад, «✕» нест мекунад баъди 40 дақ филтрҳо, ҳисобкунак ва ҳолати холӣ то дақиқаи 50-ум захира: баъди F5 ҳама чиз ба ҷояш. Ин MVP аст, минбаъд — бонусҳо ва зебоӣ
Агар шумо ақиб мемонед
Воҳима накунед ва бонус илова накунед. Қолаби оғозиро аз бахши 10 кушоед — он шаклро, render-ро ва сохторро пӯшонидааст. Панҷ TODO-ро ба итмом расонед, ва вақти боқимондаро ба санҷиш бо паём, услубҳо ва README сарф кунед. Лоиҳаи оддии корӣ аз лоиҳаи мураккаби нотамом беҳтар аст.
ЗС дар амалиёт — аз рӯи қоидаҳои курс
Copilot фаъол аст, аммо: аввал 15 дақиқа худатон; шарҳ пурсед, на танҳо код; ҳар чиро, ки гузоштед, шумо вазифадоред сатр ба сатр шарҳ диҳед. Дар охири дарс омӯзгор ҳақ дорад дар бораи ҳар сатр бипурсад. Роҳи хуби истифодаи ЗС имрӯз — пурсидан: «Шарҳ деҳ, чаро дар коди ман баъди аз нав бор шудан вазифаҳо такрор мешаванд» ва кодатонро ва тавсифи хаторо замима кунед, на «чунон кун, ки лозим аст» талаб кунед.
12 Code review: якдигарро месанҷем
Code review — вақте ки як барномасоз коди дигарро пеш аз он ки он «ба олам биравад», мехонад. Ин имтиҳон нест ва ҷустуҷӯи гунаҳкор нест: назари тоза онро мебинад, ки муаллиф кайҳо мушоҳида карданро бас кардааст. Дар дастаҳои воқеӣ бе ревью код умуман қабул намешавад.
Муқоиса аз ҳаёт
Пеш аз тӯй палавро на танҳо ошпаз, балки боз ду-се нафар чашида мебинанд: ошпаз ба маза одат кардааст ва метавонад нафаҳмад, ки намак кам аст. Ревью — ҳамон «чашидани аз берун» аст.
Ревью чӣ тавр мегузарад (10 дақиқа барои лоиҳа)
2 дақ — оғоз. Муаллиф барномаро нишон медиҳад, баррасикунанда худаш онро вайрон кардан мехоҳад.
5 дақ — хондани код. Баррасикунанда аз рӯи чек-листи зер мегузарад ва эродҳоро менависад.
3 дақ — гуфтугӯ. Се банди «чӣ хуб аст», се — «чиро беҳтар кардан». Муаллиф саволҳои равшанкунанда медиҳад ва қарор медиҳад, чиро қабул кунад.
Чек-листи баррасикунанда
Вайрон кардан мехоҳем (оғоз)
☐ Сатри холӣ ва танҳо фосилаҳо илова намешаванд
☐ Enter дар майдон мисли тугма кор мекунад
☐ Номи хеле дароз тарҳро вайрон намекунад
☐ Номи <b>test</b> ҳамчун матн нишон дода мешавад
☐ Миёнаи рӯйхатро нест кардем, навро илова кардем — ҳама чиз кор мекунад
☐ F5 — маълумот ба ҷояш
☐ Ба localStorage дастӣ хасу хошок навиштан, F5 — барнома зинда аст
☐ Дар консол хатои сурх нест
☐ Дар паҳноии 360 px ҳама чиз хонданӣ аст
Код мехонем
☐ Як объекти ҳолат, на тағйирёбандаҳои пароканда
☐ render интерфейсро аз ҳолат месозад ва рӯйхатро пок мекунад
☐ Функсияҳо болои ҳолат ҳолати кӯҳнаро тағйир намедиҳанд
☐ preventDefault ва санҷиш ҳаст
☐ Ҳодисаҳои рӯйхат — тавассути вакилкунӣ, на дар ҳар элемент
☐ Матни корбар тавассути textContent
☐ Хондан аз localStorage бо try/catch муҳофизат шудааст
☐ Номҳои фаҳмо, a, x, data2 нест
☐ Нусхабардорӣ, коди шарҳшуда ва console.log-и зиёдатӣ нест
☐ Сатрҳои «ҷодугарӣ» ("done", калиди анбор) ба константаҳо баровардаанд
Эродҳоро чӣ тавр навиштан
Бад
«Код бад аст»
«Ҳамаро аз нав кун»
«Ту нодуруст ном гузоштӣ»
Хуб
«Дар script.js:42 id ҳамчун length + 1 ҳисоб мешавад. Баъди нест кардан рақамҳо такрор мешаванд. Шояд nextId-ро нигоҳ дорем?»
«Хуб аст, ки render кӯтоҳ аст ва аз боло ба поён хонда мешавад»
«Тағйирёбандаи d дар toggle — ин чист? Шояд task?»
Формулаи эрод: дар куҷо (файл ва сатр) → чӣ мебинам → чаро муҳим аст → пешниҳод (беҳтараш ҳамчун савол). Кодро танқид мекунем, на одамро. Баррасикунанда коди бегонаро ба ҷои муаллиф аз нав намесозад.
ЗС ҳамчун баррасикунандаи дуюм — баъди одамон, на ба ҷои онҳо
Вақте ҷуфт тамом кард, кодро аз ЗС гузаронидан мумкин аст: «Кодро аз рӯи чек-лист санҷ: номҳо, андозаи функсияҳо, такрор, баргашти барвақт, ҷудокунии мантиқ ва намоиш. Танҳо эродҳо, бе аз нав навиштан». На ҳамаи маслиҳатҳоро қабул кунед — ҳар ислоҳро шумо бояд асоснок карда тавонед.
Барои муфассалтар хондан: learn.javascript.ru — отладка в браузере
Амалиёт: ревью дар миниатюра
ВАЗИФАИ 12.1 Эрод аз баррасикунанда: id-ҳо такрор мешаванд миёна
Баррасикунанда навишт: «Баъди нест кардани вазифа аз миёна нав рақами аллакай ишғолшударо мегирад». Санҷед ва ислоҳ кунед: addTask бояд state.nextId-ро истифода барад ва онро зиёд кунад. Рақамҳои 1,3,4-ро интизорем, аммо такрор мегирем.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
function addTask (state, title) {
const id = state.tasks.length + 1 ;
return { ... state, tasks: [... state.tasks, { id, title, done: false }] };
}
let s = { tasks: [], nextId: 1 };
s = addTask (s, "Плов" );
s = addTask (s, "Чой" );
s = addTask (s, "Самбуса" );
s = { ... s, tasks: s.tasks.filter ((t) => t.id !== 2 ) }; // «Чой»-ро нест кардем
s = addTask (s, "Курутоб" );
console.log (s.tasks.map ((t) => t.id).join ("," ));
Натиҷаи интизоршаванда 1,3,4
Ишора 1 Пайгирӣ кунед: баъди нест кардан дар массив ду вазифа ҳаст — length + 1 3 медиҳад, ва чунин рақам аллакай ҳаст. Рақам бояд танҳо афзояд ва аз дарозии массив вобаста набошад.
Ишора 2 const id = state.nextId; ва дар объекти баргардонидашуда nextId: id + 1-ро илова кунед.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 12.2 Эрод аз баррасикунанда: хатои чоп ва сатрҳои ҷодугарӣ осон
Филтри «Активные» ҳамаро нишон медиҳад. Баррасикунанда ба хатои чоп дар сатр шубҳа дорад. Онро ислоҳ кунед, ва ҳамзамон бо маслиҳати ревью сатрҳои филтрҳоро ба константаи FILTER (ALL, ACTIVE, DONE) бароред ва онро ҳам дар функсия ва ҳам дар даъватҳо истифода баред — ҳамин тавр хатои чоп ба хатое табдил меёбад, ки муҳаррир мебинад.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
function getVisible (tasks, filter) {
if (filter === "activ" ) return tasks.filter ((t) => !t.done);
if (filter === "done" ) return tasks.filter ((t) => t.done);
return tasks;
}
const tasks = [
{ title: "Плов" , done: true },
{ title: "Чой" , done: false },
{ title: "Самбуса" , done: false },
];
console.log (getVisible (tasks, "all" ).length);
console.log (getVisible (tasks, "active" ).length);
console.log (getVisible (tasks, "done" ).length);
Натиҷаи интизоршаванда 3
2
1
Ишора 1 Сатри шартро бо сатре, ки ҳангоми даъват дода мешавад, муқоиса кунед. Онҳо бояд то ҳарф мувофиқ бошанд.
Ишора 2 const FILTER = { ALL: "all", ACTIVE: "active", DONE: "done" }; — ва баъд дар ҳама ҷо ба ҷои сатр FILTER.ACTIVE.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
13 Ҳимоя: 5 дақиқа, ки 15 холро ҳал мекунанд
Ҳимоя — ин ҳикояи кӯтоҳ дар бораи он аст, ки шумо чӣ кардед ва чӣ тавр кор мекунад . На муаррифӣ ва на пурсиш: шумо бояд нишон диҳед, ки лоиҳа аз они шумост ва шумо онро мефаҳмед. Маҳз бинобар ҳамин ба ҳимоя 15 хол аз 100 ҷудо шудааст.
Сенария барои 5 дақиқа
Вақт Чӣ мекунед 0:00–0:30 Муаррифӣ. Бо як ибора: барнома чист, кадом вариант, барои кӣ. «Ин трекери одатҳост: рӯзро қайд мекунӣ — силсила меафзояд».0:30–2:00 Намоиш аз рӯи сенария. Илова → қайд → нест кардан → филтр → F5 ва нишон додан, ки маълумот монд. Сенарияро пешакӣ дар хона санҷед.2:00–3:30 Код. Се ҷойро нишон диҳед: объекти state, функсияи render, як коркардкунандаи ҳодисаҳо. Бо суханони худ шарҳ диҳед, сатрҳоро бо овози баланд нахонед.3:30–5:00 Саволҳо. Омӯзгор ва гурӯҳ савол медиҳанд. Намедонед — ростқавлона бигӯед ва тахмин кунед, ки ҷавобро чӣ тавр меҷустед.
Саволҳои маъмул ва дар бораи чӣ бояд гуфт
state чист ва дар ту дар куҷост? Як объект бо ҳамаи маълумоти барнома: рӯйхат, филтр, id-и навбатӣ. Саҳифа аз он кашида мешавад. Онро дар код нишон диҳед.
Чаро render ҳар дафъа рӯйхатро аз нав месозад? Осонтар ва боэътимодтар: ҷустан лозим нест, ки кадом элемент тағйир ёфт. Саҳифа ҳамеша ба ҳолат мувофиқ аст. Барои рӯйхати хурд ин зуд аст.
Вакилкунӣ чист ва чаро дар ин ҷо лозим аст? Як коркардкунанда дар рӯйхат ба ҷои коркардкунанда дар ҳар тугма. Баъди render элементҳо аз нав сохта мешаванд, аммо коркардкунанда дар падар мемонад ва барои элементҳои нав кор мекунад.
Чаро дар submit preventDefault лозим аст? Бе он браузер шаклро мефиристад ва саҳифаро аз нав бор мекунад — ҳолат дар хотира гум мешавад.
Дар localStorage чӣ ва бо кадом намуд мемонад? Сатри JSON бо ҳолат таҳти калиди лоиҳа. Анбор танҳо сатрҳоро мефаҳмад, бинобар ин JSON.stringify ҳангоми навиштан ва JSON.parse ҳангоми хондан.
Агар дар анбор хасу хошок бошад, чӣ мешавад? try/catch дар атрофи JSON.parse ва санҷиши шакл: ҳангоми мушкилот барнома бо ҳолати холӣ оғоз мешавад ва намеафтад.
Id дар ту чӣ тавр ҳисоб мешавад? Баъди нест кардан чӣ? Тавассути ҳисобкунаки алоҳидаи nextId, ки танҳо меафзояд. length + 1 такрор медод.
Чаро textContent, на innerHTML? Матни корбарро ҳамчун аломатгузорӣ қабул кардан мумкин нест: вагарна ба барнома HTML ва скриптҳои бегонаро андохтан мумкин аст.
ЗС-ро дар куҷо истифода кардӣ? Ин сатрро шарҳ деҳ. Ростқавлона бигӯед, барои чӣ: декомпозитсия, шарҳи хато, санҷиш. Ҳар сатре, ки омӯзгор нишон дод, бояд бо суханони худ шарҳ дода шавад.
Агар боз як рӯз медоштӣ, чиро беҳтар мекардӣ? 1–2 чизи мушаххасро ном баред: таҳрир, ҷустуҷӯ, санҷишҳо. Ин нишон медиҳад, ки шумо маҳдудиятҳои лоиҳаро мебинед.
Маслиҳатҳо барои омодагӣ
Сенарияи намоишро бо овози баланд бо секундомер ақаллан як маротиба гузаред.
Файлҳои лозимиро пешакӣ кушоед ва ҳарфро дар муҳаррир калон кунед: гурӯҳ бояд кодро бубинад.
Зиёдатиро гирифта партоед: коди шарҳшуда, console.log, маълумоти санҷишӣ дар анбор.
Узр нахоҳед («ман муваффақ нашудам»). Беҳтар: «ин нест, зеро… инак ман онро чӣ тавр илова мекардам».
Ҷавобро намедонед — ин муқаррарӣ аст. Бигӯед «ба ёдам нест, аммо кӯшиш мекунам дар ҳуҷҷатҳо ёбам ва нишон медиҳам» — ин аз ҳадс задан беҳтар баҳо дода мешавад.
Амалиёт: машқи пешакӣ
ВАЗИФАИ 13.1 Ба саволҳои ҳимоя омода шавед осон
Саволҳои болоро хонед ва ба панҷтои онҳо дар бораи лоиҳаи худ , бо суханони худ, бо як-ду ҷумла ҷавоб диҳед. Ҷавобҳоро ба объекти зер нависед (ин танҳо ёддоштҳост — санҷиши худкор дар ин ҷо нест), баъд онҳоро бо овози баланд дар назди ҳамсояи ҷуфт машқ кунед. Вақте ҷавоб додед — вазифаро дастӣ қайд кунед.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const defence = {
state: "Мой state — объект с полями ... Он лежит в ..." ,
render: "" ,
delegation: "" ,
storage: "" ,
improve: "" ,
};
console.log (Object.keys (defence).length + " ответов подготовлено" );
Ишора 1 Ҷавоб диҳед, мисли ин ки ба дӯсте шарҳ медиҳед, ки ҳеҷ гоҳ кодатонро надидааст: кӯтоҳ ва бо мисол аз лоиҳаи шумо.
Ишора 2 Ҷавоби хуб тафсилоти мушаххас дорад: «дар коди ман render дар сатри 40-ум аст ва аз commit даъват мешавад», на «хуб, он чизеро мекашад».
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
14 Бор кардани лоиҳа ба GitHub
Лоиҳае, ки танҳо дар ноутбуки шумост, барои корфармо вуҷуд надорад. GitHub — портфолиои шумост. Git-и асосӣ (init, commit, push)-ро шумо аз талаботи воридшавии курс медонед; мунтазам онро дар дарси 19 таҳлил мекунем, ва имрӯз — роҳи ҳадди ақали «папка → репозиторий».
Репозиторий созед. Дар github.com New repository -ро пахш кунед. Ном — бо забони англисӣ, бо дефис: task-tracker ё habit-tracker. Public -ро интихоб кунед. Нишонаҳои «Add a README», «.gitignore» ва «license»-ро нагузоред — репозиторий бояд холӣ бошад.
Git-ро дар папкаи лоиҳа ибтидо кунед ва коммити аввалро созед:
Терминал (дар папкаи лоиҳа)
git init
git add .
git commit -m "add tracker app"
Репозиторийро пайваст кунед ва кодро фиристед. Суроғаро аз саҳифаи репозиторийи нав нусха кунед (ба ҷои ВАШ_ЛОГИН номи худро дар GitHub гузоред):
Терминал
git branch -M main
git remote add origin https://github.com/ВАШ_ЛОГИН/task-tracker.git
git push -u origin main
Натиҷаро санҷед. Саҳифаи репозиторийро нав кунед: файлҳо ба ҷояшон, дар реша index.html намоён аст. Репозиторийро дар тирезаи хусусии браузер ё аз телефон кушоед — истинод бояд бе вуруд ба ҳисоб кушода шавад.
README.md-ро аз рӯи қолаби зер илова кунед, скриншоти барномаро гиред ва ба репозиторий гузоред.
Ислоҳотро аз рӯи ревью бо коммитҳои алоҳида бор кунед — ҳамин тавр дар таърих намоён аст, ки шумо чиро такмил додед:
Терминал
git add .
git commit -m "fix duplicate ids after delete"
git push
Коммитҳоро чӣ тавр ном гузоштан
Кӯтоҳ, бо забони англисӣ, бо ҳарфи хурд, бо феъл дар шакли амрӣ: add task filters, fix empty title validation, remove dead code. Не update, не fix, не aaa. Ақаллан 5 коммити бомаънӣ барои лоиҳа — нишони хуби кори озода аст.
README.md — қолаб
# Трекер задач
Приложение на чистом JavaScript: добавление, отметка и удаление задач,
фильтры, счётчик. Данные сохраняются в localStorage.
## Что умеет
- добавлять задачи (с проверкой на пустую строку)
- отмечать выполненными и удалять
- фильтры «Все / Активные / Готовые»
- помнить данные после перезагрузки
## Стек
HTML, CSS, JavaScript (без библиотек)
## Запуск
Откройте index.html в браузере.
## Скриншот

## Что исправил после code review
- ...
## Что можно улучшить
- ...
Фаромӯш накунед
README-ро бо суханони худ нависед. Агар шумо матнро аз ЗС бе ислоҳ гузошта бошед, ин фавран намоён аст — ва дар ҳимоя шумо онро нақл карда наметавонед. Инчунин ба репозиторий зиёдатиро бор накунед: ёддоштҳои шахсӣ, паролҳо, калидҳо.
Барои муфассалтар хондан: GitHub Docs — Hello World
15 Вазифаи хонагӣ
Лоиҳаро аз рӯи эродҳои ревью ва ҳимоя такмил диҳед ва онро ба GitHub бор кунед.
Чӣ бояд кард
☐ Эродҳоеро, ки шумо дар ревью ва ҳимоя қабул кардед, ислоҳ кунед.
☐ Ҳамаи бандҳои MVP-ро аз бахши 02 санҷед ва чек-листи баррасикунандаро аз рӯи лоиҳаи худ боз як бор гузаред.
☐ Аз код console.log-и зиёдатӣ, коди шарҳшуда ва функсияҳои мурдаро бароред.
☐ README.md-ро нависед (ин чист, стек, оғоз, скриншот, чиро ислоҳ кардед, чиро беҳтар кардан мумкин).
☐ Лоиҳаро ба GitHub бор кунед: репозиторий оммавӣ, на камтар аз 5 коммити бомаънӣ.
☐ Агар ҳимояро ҳанӯз нагузашта бошед — аз рӯи бахши 13 омода шавед.
Чиро супорид
Истинод ба репозиторий дар чати гурӯҳ (Telegram). Дар паём нависед: варианти лоиҳа (А ё Б), баъди ревью чиро илова кардед, кадом бонусро кардед (агар кардед).
Вазифаи хонагӣ чӣ тавр баҳо дода мешавад (0–10)
Чиро месанҷем Холҳо Истинод бе вуруд кушода мешавад, репозиторий оммавӣ, дар реша index.html ҳаст 2 Эродҳои ревью ислоҳ шудаанд (дар коммитҳо намоён аст) 3 README бо тавсиф ва скриншот, бо суханони худӣ навишта шудааст 2 На камтар аз 5 коммити бомаънӣ бо паёмҳои фаҳмо 2 Барнома бе хато дар консол кушода мешавад 1
Ин баҳо барои вазифаи хонагии дарс аст (0–10). Баҳо барои худи лоиҳаи хурд (0–100) аз рӯи ҷадвали бахши 03 мегузорад ва алоҳида ҳисоб карда мешавад.
✓ Ёддошти дарс
Лоиҳа: трекери вазифаҳо (А) ё одатҳо (Б) бо JS-и холис. Баҳо 0–100: функсионалият 25, DOM 15, ҳодисаҳо ва шаклҳо 15, ҳолат ва localStorage 15, сохтори код 10, интерфейс 5, ҳимоя 15; бонус то +5.
Аввал MVP: шакл бо санҷиш, қайд, нест кардан, филтрҳо, ҳисобкунак, захира. Бонусҳо — баъдтар.
Декомпозитсия бо ЗС: промпт аз рӯи формулаи курс → зиёдатиро хат задан → тартибро санҷидан → вақтро худатон баҳо додан (×1.5) → қадам аз 40 дақиқа дарозтар не → дар ҳар қадам натиҷаи намоён.
Меъморӣ: ҳолат → функсияҳои тоза (навро бармегардонанд) → render() → commit(next) (ҳолат + захира + аз нав кашидан) → ҳодисаҳо.
Рӯйхат: як коркардкунанда дар падар (вакилкунӣ), event.target.closest(...), dataset барои id.
Шакл: preventDefault, trim, холиро илова намекунем. Матни корбар — тавассути textContent.
localStorage: танҳо сатрҳо → JSON.stringify / JSON.parse; хондан дар try/catch + санҷиши шакл; калид бо префикси "tracker:v1". Дар қуттии санҷиши саҳифа он банд аст — тавассути ивазкунак бо ҳамон API кор мекунем.
id: ҳисобкунаки алоҳидаи nextId, на length + 1.
Ревью: оғоз (вайрон кардан мехоҳем) → хондан аз рӯи чек-лист → гуфтугӯ: 3 «хуб» ва 3 «беҳтар кардан». Эрод = дар куҷо, чӣ мебинам, чаро, пешниҳод.
Ҳимоя (5 дақ): 0:30 муаррифӣ, 1:30 намоиш бо F5, 1:30 код (state, render, коркардкунанда), 1:30 саволҳо. Ҳар сатрро бо суханони худ шарҳ медиҳем.
GitHub: git init → add → commit → remote add origin → push -u origin main; README бо скриншот; коммитҳо бомаънӣ ва бо забони англисӣ.