4 травня 2025 р.

LocalStorage, sessionStorage

Об’єкти веб-сховища localStorage та sessionStorage дозволяють зберігати дані в браузері у вигляди пар ключ/значення.

Що цікаво, дані зберігаються навіть після оновлення сторінки (для sessionStorage) і після повного закриття і нового відкриття вікна браузера (для localStorage). Ми скоро перевіримо це на практиці.

Ми вже маємо cookies. Навіщо додаткові об’єкти?

  • На відміну від файлів cookies, об’єкти веб-сховища не надсилаються на сервер із кожним запитом. Завдяки цьому ми можемо зберігати набагато більше даних. Більшість браузерів дозволяють принаймні 5 мегабайтів даних (або більше), користувач може навіть змінити цей об’єм.
  • Крім того, на відміну від файлів cookies, сервер не може маніпулювати об’єктами сховища через HTTP-заголовки. Все зроблено на JavaScript.
  • Сховище прив’язане до оригінального сайту (домен/протокол/порт). Таким чином, що різні протоколи або субдомени мають різні об’єкти зберігання, і не можуть отримати доступ до даних один одного.

Обидва об’єкти сховища забезпечують однакові методи та властивості:

  • setItem(key, value) – зберегти пару ключ/значення.
  • getItem(key) – отримати значення за ключем.
  • removeItem(key) – видалити дані за ключем.
  • clear() – видалити все.
  • key(index) – отримати ключ на заданій позиції.
  • length – кількість збережених елементів.

Як ви можете бачити, це схоже на колекцію Map (setItem/getItem/removeItem), але також дозволяє отримати доступ за індексом за допомогою key(index).

Подивімося, як це працює.

Демонстрація роботи localStorage

Основними особливостями localStorage є:

  • Спільний доступ з усіх вкладок і вікон для одного і того ж самого сайту.
  • Термін дії даних не закінчується. Дані залишаються після перезавантаження браузера і навіть перезавантаження ОС.

Наприклад, якщо ви запустите цей код…

localStorage.setItem('test', 1);

…І закриєте/відкриєте браузер або просто відкриєте ту саму сторінку в іншому вікні, то зможете отримати дані так:

alert( localStorage.getItem('test') ); // 1

Ми повинні бути на тому ж самому сайті (домен/порт/протокол), шлях URL-адреси може відрізнятись

localStorage доступний для одного сайту в усіх відкритих вікнах, тому якщо ми встановимо дані в одному вікні, зміна стане видимою в іншому.

Доступ як до звичайного об’єкта

Ми також можемо використовувати простий об’єктний спосіб отримання/запису даних, наприклад:

// записати дані за ключем
localStorage.test = 2;

// отримати дані за ключем
alert( localStorage.test ); // 2

// видалити дані
delete localStorage.test;

Це дозволено з історичних причин і в цілому працює, але зазвичай не рекомендується, оскільки:

  1. Якщо ключ створений користувачем, він може бути будь-яким, наприклад, length або toString, або іншим вбудованим методом localStorage. У цьому випадку getItem/setItem працює нормально, тоді як доступ через об’єкт ні:

    let key = 'length';
    localStorage[key] = 5; // Помилка, не вдається задати length
  2. Існує подія storage, вона запускається, коли ми змінюємо дані. Ця подія не відбувається при зміні даних без виклику setItem. Ми поговоримо про це пізніше в цьому розділі.

Перебір ключів

Як ми бачили, методи забезпечують функцію “отримати/записати/видалити за ключем”. Але як отримати всі збережені значення чи ключі?

На жаль, об’єкти зберігання не є ітераційними.

Один зі способів – працювати з ними як з масивом:

for(let i=0; i<localStorage.length; i++) {
  let key = localStorage.key(i);
  alert(`${key}: ${localStorage.getItem(key)}`);
}

Інший спосіб – використати цикл for key in localStorage, так само, як для звичайних об’єктів.

Він перебирає ключі, але також виводить кілька вбудованих властивостей, які нам не потрібні:

// невдала спроба
for(let key in localStorage) {
  alert(key); // показує getItem, setItem та інші вбудовані властивості
}

…Тож нам потрібно або відфільтрувати поля з прототипу за допомогою перевірки hasOwnProperty:

for(let key in localStorage) {
  if (!localStorage.hasOwnProperty(key)) {
    continue; // пропускати ключі, такі як "setItem", "getItem" тощо
  }
  alert(`${key}: ${localStorage.getItem(key)}`);
}

…Або просто отримати “власні” ключі за допомогою Object.keys, а потім перебрати їх, якщо потрібно:

let keys = Object.keys(localStorage);
for(let key of keys) {
  alert(`${key}: ${localStorage.getItem(key)}`);
}

Останній варіант працює, оскільки Object.keys повертає лише ключі, які належать об’єкту, ігноруючи прототип.

Тільки рядки

Зверніть увагу, що і ключ, і значення мають бути рядками.

Якщо ми спробуємо використати будь-який інший тип, наприклад число або об’єкт, він автоматично перетвориться на рядок:

localStorage.user = {name: "John"};
alert(localStorage.user); // [object Object]

Однак ми можемо використати JSON для зберігання об’єктів:

localStorage.user = JSON.stringify({name: "Тарас"});

// через деякий час
let user = JSON.parse( localStorage.user );
alert( user.name ); // Тарас

Також можна перетворити весь об’єкт сховища на JSON рядок, наприклад, під час налагодження коду:

// додано параметри форматування до JSON.stringify, щоб об’єкт виглядав краще
alert( JSON.stringify(localStorage, null, 2) );

sessionStorage

Об’єкт sessionStorage використовується набагато рідше, ніж localStorage.

Властивості та методи ті самі, але можливості більш обмежені:

  • sessionStorage існує лише на поточній вкладці браузера.
    • Інша вкладка з тією ж сторінкою матиме інше сховище.
    • Але він використовується між iframes на одній вкладці (за умови, що це один сайт).