Урок 17 из 49 · Месяц 2. Git и введение в JavaScript
JSON, localStorage, sessionStorage и DevTools
Содержание урока
- Формат JSON
- Правила JSON
- JSON.stringify — объект в строку
- JSON.parse — строка в объект
- Ошибки разбора
- Хранилища браузера: localStorage и sessionStorage
- Чем они отличаются
- Основные методы
- Хранятся только строки
- Удобные функции-помощники
- Пример: тема, которая запоминается
- Пример: sessionStorage для черновика формы
- DevTools — инструменты разработчика
- Основные вкладки
- Console: больше, чем console.log
- Application: смотрим хранилища
- Debugging: пошаговая отладка
- Network: что загрузилось
- Типичные ошибки
- Практика
- Итоги
В этом уроке три темы, которые пригодятся каждый день. JSON — универсальный формат, в котором программы обмениваются данными. localStorage и sessionStorage — хранилища в браузере, благодаря которым список дел или тёмная тема не пропадают после перезагрузки страницы. А DevTools — инструменты разработчика, с помощью которых ищут и исправляют ошибки в коде.
Формат JSON
JSON (JavaScript Object Notation) — текстовый формат для хранения и передачи данных. Сервер присылает данные в JSON, приложения сохраняют настройки в JSON, файл package.json в любом проекте — тоже JSON. Аналогия: JSON — это «общий язык» программ, как английский в аэропорту: на чём бы ни была написана программа, JSON она понимает.
Выглядит JSON почти как объект JavaScript:
{
"id": 1,
"name": "Алина",
"age": 21,
"isStudent": true,
"skills": ["HTML", "CSS", "JavaScript"],
"address": {
"city": "Бишкек",
"zip": null
}
}
Правила JSON
JSON строже, чем объекты JavaScript:
- ключи всегда в двойных кавычках:
"name", а неname; - строки — только в двойных кавычках, одинарные запрещены;
- нет запятой после последнего элемента;
- нет комментариев;
- разрешённые значения: строка, число,
true/false,null, массив, объект. Функций,undefined, дат как объектов в JSON нет.
| JavaScript-объект | JSON |
|---|---|
{ name: 'Ali' } |
{ "name": "Ali" } |
{ a: 1, } (запятая в конце) |
{ "a": 1 } |
{ fn() {} } |
функции недопустимы |
{ x: undefined } |
свойство пропадает |
JSON.stringify — объект в строку
const user = { name: "Алина", age: 21, skills: ["HTML", "CSS"] };
const json = JSON.stringify(user);
console.log(json); // '{"name":"Алина","age":21,"skills":["HTML","CSS"]}'
console.log(typeof json); // "string"
JSON.stringify превращает объект или массив в строку — её можно отправить на сервер или сохранить. Для красивого вывода с отступами передайте третий аргумент:
console.log(JSON.stringify(user, null, 2));
JSON.parse — строка в объект
const text = '{"title":"Кружка","price":350,"tags":["посуда","подарок"]}';
const product = JSON.parse(text);
console.log(product.title); // "Кружка"
console.log(product.tags[1]); // "подарок"
JSON.parse делает обратное: из строки получает настоящий объект, с которым можно работать.
Объект —— JSON.stringify ——> Строка
Объект <—— JSON.parse —— Строка
Ошибки разбора
Если строка — не корректный JSON, JSON.parse выбросит ошибку и остановит скрипт. Поэтому данные из ненадёжных источников разбирают внутри try...catch (подробно о нём — в уроке try, catch, finally):
const broken = "{ name: 'Ali' }"; // ключ без кавычек, одинарные кавычки
try {
const data = JSON.parse(broken);
console.log(data);
} catch (error) {
console.log("Не получилось разобрать JSON:", error.message);
}
Хранилища браузера: localStorage и sessionStorage
Обычно все переменные JavaScript исчезают при перезагрузке страницы. Если пользователь добавил задачи в список и нажал F5 — всё пропало. Чтобы данные сохранялись, браузер даёт два хранилища — Web Storage.
Аналогия: переменные — это записи мелом на доске (стираются после урока), а localStorage — тетрадь, которая остаётся у вас.
Чем они отличаются
localStorage |
sessionStorage |
|
|---|---|---|
| Сколько хранится | Пока не удалят (код или пользователь) | Пока открыта вкладка |
| После перезагрузки | Сохраняется | Сохраняется |
| После закрытия вкладки | Сохраняется | Удаляется |
| В других вкладках сайта | Доступно | У каждой вкладки своё |
| Объём | Около 5 МБ на сайт | Около 5 МБ на сайт |
Данные привязаны к сайту (домену): localStorage одного сайта не видят другие сайты.
Основные методы
У обоих хранилищ одинаковые методы:
localStorage.setItem("theme", "dark"); // сохранить: ключ и значение
const theme = localStorage.getItem("theme"); // прочитать → "dark"
localStorage.removeItem("theme"); // удалить один ключ
localStorage.clear(); // удалить всё хранилище сайта
console.log(localStorage.getItem("unknown")); // null — такого ключа нет
Для sessionStorage всё то же самое: sessionStorage.setItem("step", "2").
Хранятся только строки
Главная особенность: хранилище умеет сохранять только строки. Числа превращаются в строки, а объекты — в бесполезное "[object Object]":
localStorage.setItem("count", 5);
console.log(typeof localStorage.getItem("count")); // "string"
localStorage.setItem("user", { name: "Ali" });
console.log(localStorage.getItem("user")); // "[object Object]" — данные потеряны
Решение — JSON: при сохранении JSON.stringify, при чтении JSON.parse.
const todos = [
{ id: 1, text: "Выучить JSON", done: true },
{ id: 2, text: "Сделать ToDo", done: false },
];
localStorage.setItem("todos", JSON.stringify(todos));
const saved = JSON.parse(localStorage.getItem("todos")) ?? [];
console.log(saved[1].text); // "Сделать ToDo"
?? [] здесь подстраховывает: если ключа нет, getItem вернёт null, JSON.parse(null) тоже даст null, и мы подставим пустой массив (оператор ?? разбирали в уроке Деструктуризация, spread, rest, ?. и ??).
Удобные функции-помощники
function saveToStorage(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
function loadFromStorage(key, defaultValue) {
try {
const raw = localStorage.getItem(key);
return raw === null ? defaultValue : JSON.parse(raw);
} catch {
return defaultValue; // в хранилище оказался «битый» JSON
}
}
saveToStorage("settings", { theme: "dark", fontSize: 18 });
const settings = loadFromStorage("settings", { theme: "light", fontSize: 16 });
console.log(settings.theme); // "dark"
Пример: тема, которая запоминается
<button id="theme-btn">Сменить тему</button>
body.dark {
background: #111827;
color: #f9fafb;
}
const themeBtn = document.querySelector("#theme-btn");
if (localStorage.getItem("theme") === "dark") {
document.body.classList.add("dark");
}
themeBtn.addEventListener("click", () => {
document.body.classList.toggle("dark");
const isDark = document.body.classList.contains("dark");
localStorage.setItem("theme", isDark ? "dark" : "light");
});
- При загрузке страницы читаем сохранённую тему и сразу применяем её.
- По клику переключаем класс
darkуbody(как в уроке Введение в DOM). - Записываем новое значение в
localStorage— после перезагрузки тема останется.
Пример: sessionStorage для черновика формы
sessionStorage подходит для временных данных, которые нужны только в текущей вкладке, — например, черновик формы:
const textarea = document.querySelector("#comment");
textarea.value = sessionStorage.getItem("draft") ?? "";
textarea.addEventListener("input", () => {
sessionStorage.setItem("draft", textarea.value);
});
Пользователь случайно обновил страницу — текст на месте. Закрыл вкладку — черновик исчез, как и должно быть.
DevTools — инструменты разработчика
DevTools — встроенный в браузер набор инструментов для изучения и отладки страницы. Открывается клавишей F12 или Ctrl + Shift + I (на Mac — Cmd + Option + I). Также можно кликнуть правой кнопкой по элементу и выбрать «Просмотреть код» (Inspect). Ниже — названия вкладок в Chrome, в других браузерах они похожи.
Основные вкладки
| Вкладка | Для чего |
|---|---|
| Elements | Дерево DOM и стили: можно менять HTML и CSS прямо на лету |
| Console | Вывод console.log, ошибки, выполнение JS-команд |
| Sources | Файлы скриптов, точки останова, пошаговая отладка |
| Network | Все запросы страницы: файлы, картинки, запросы к API |
| Application | localStorage, sessionStorage, cookies |
Console: больше, чем console.log
const users = [
{ name: "Ali", age: 25 },
{ name: "Aida", age: 22 },
];
console.log("Обычный вывод");
console.warn("Предупреждение — жёлтым");
console.error("Ошибка — красным");
console.table(users); // красивая таблица из массива объектов
console.log({ users }); // выводит переменную вместе с её именем
В консоли можно и выполнять код: напишите document.title или localStorage и нажмите Enter.
Когда в коде ошибка, консоль показывает её текст и ссылку на файл и строку, например script.js:12. Кликните по ссылке — DevTools откроет нужное место во вкладке Sources. Читайте текст ошибки целиком — обычно в нём уже сказано, что не так:
Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')
at script.js:3
Перевод: «на строке 3 вы вызвали addEventListener у null» — значит, querySelector не нашёл элемент.
Application: смотрим хранилища
Во вкладке Application слева есть раздел Storage → Local storage и Session storage. Выберите адрес сайта — увидите таблицу ключей и значений. Значения можно редактировать двойным кликом и удалять, а это удобно, чтобы проверить, как приложение ведёт себя с пустым или «сломанным» хранилищем.
Debugging: пошаговая отладка
Отладка (debugging) — поиск и исправление ошибок. console.log хорош, но когда логика сложная, удобнее остановить программу в нужном месте и посмотреть значения всех переменных.
Возьмём функцию с ошибкой:
function getTotal(cart) {
let total = 0;
for (let i = 0; i <= cart.length; i++) {
total += cart[i].price * cart[i].qty;
}
return total;
}
console.log(getTotal([{ price: 100, qty: 2 }, { price: 50, qty: 1 }]));
Код падает с ошибкой Cannot read properties of undefined (reading 'price'). Найдём причину:
- Точка останова (breakpoint). Откройте Sources, найдите
script.jsи кликните по номеру строкиtotal += ...— появится синяя метка. Или напишите в коде строкуdebugger;— браузер остановится на ней, когда DevTools открыты. - Перезагрузите страницу. Выполнение остановится на метке, а справа в панели Scope будут видны значения
i,total,cart. - Шаг вперёд. Кнопка Step over (или
F10) выполняет одну строку. Кнопка Resume (F8) — продолжить до следующей точки. - Наблюдение. Видим:
cart.lengthравно2, а цикл доходит доi = 2. Элементаcart[2]нет — этоundefined. - Исправление: условие должно быть
i < cart.length.
| Кнопка | Клавиша | Что делает |
|---|---|---|
| Resume | F8 |
Продолжить до следующей точки останова |
| Step over | F10 |
Выполнить строку, не заходя внутрь функций |
| Step into | F11 |
Зайти внутрь вызываемой функции |
| Step out | Shift + F11 |
Выйти из текущей функции |
Ещё полезно: в панели Watch можно добавить выражение (например, cart[i]) и следить, как оно меняется на каждом шаге.
Network: что загрузилось
Во вкладке Network видно все запросы страницы: статус (200 — успешно, 404 — не найдено), размер и время загрузки. Если стили или картинка не применились, проверьте здесь, не стоит ли у файла 404 — обычно это ошибка в пути. Запросы к серверу через fetch будем разбирать в уроке fetch, async/await и GET, и Network станет главным помощником.
Подробное руководство — в официальной документации Chrome DevTools.
Типичные ошибки
- Сохранение объекта без
JSON.stringify— в хранилище окажется"[object Object]". - Забыли
JSON.parseпри чтении — работаете со строкой вместо массива,todos.mapне существует. - Одинарные кавычки или запятая в конце в JSON-строке —
SyntaxErrorпри разборе. - Ожидание числа из хранилища —
getItemвсегда возвращает строку илиnull, приводите черезNumber(). - Секреты в localStorage — их может прочитать любой скрипт на странице.
- Игнорирование текста ошибки в консоли — в нём почти всегда есть ответ.
Практика
- Туда и обратно. Создайте объект книги с массивом авторов, превратите его в JSON через
JSON.stringify(book, null, 2), выведите, затем разберите обратно и выведите второго автора. Ожидаемый результат: красиво отформатированный JSON и имя автора. - Счётчик посещений. При каждой загрузке страницы увеличивайте число в
localStorageи выводите «Вы были здесь N раз». Ожидаемый результат: число растёт после каждой перезагрузки и не сбрасывается после закрытия браузера. - Шаг формы в sessionStorage. Сделайте форму из трёх шагов (кнопки «Далее»/«Назад»), текущий шаг храните в
sessionStorage. Ожидаемый результат: после перезагрузки вы остаётесь на том же шаге, в новой вкладке — снова на первом. - ToDo с сохранением. Возьмите список дел из урока про DOM и сохраняйте массив задач в
localStorageпри каждом изменении. Ожидаемый результат: после перезагрузки задачи и их статус «выполнено» на месте; в Application → Local storage виден JSON. - Охота на баг. Скопируйте функцию
getTotalс ошибкой, поставьте breakpoint в DevTools, пройдите цикл через Step over и найдите причину. Ожидаемый результат: вы исправили условие цикла и можете объяснить, на каком шаге появилсяundefined.
Итоги
- JSON — текстовый формат данных: ключи и строки в двойных кавычках, без комментариев и функций.
JSON.stringifyпревращает объект в строку,JSON.parse— строку обратно в объект.localStorageхранит данные бессрочно,sessionStorage— пока открыта вкладка; оба — только строки.- Объекты и массивы сохраняйте через
JSON.stringify, читайте черезJSON.parseс запасным значением. - DevTools: Elements — DOM и стили, Console — ошибки и вывод, Sources — отладка, Network — запросы, Application — хранилища.
- Breakpoint и пошаговое выполнение помогают увидеть значения переменных в момент ошибки.