Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
⚡ Days 15–22 – Advanced & Async JavaScript  ·  Day 15

Day 15: localStorage, sessionStorage & JSON

⏱ 85 min📶 Intermediate🎯 100% self-study
Day 15 / 30

✅ Today you will learn

  • localStorage vs sessionStorage vs cookies vs IndexedDB
  • setItem, getItem, removeItem – strings only
  • Saving objects and arrays with JSON
  • A safe storage helper with defaults, versioning and try/catch
  • Real uses: cart, theme, form drafts – and what never to store

🏢 In the real world

A customer fills her cart with 4 sweets, gets a phone call, closes the tab – and comes back to an empty cart. She leaves. Studies of online shops consistently show that a remembered cart brings back a meaningful share of buyers. Remembering a cart, the chosen theme and a half-typed message is all done with Web Storage.

Where can a browser keep data?

StorageLifetimeSizeSent to server?Use for
localStorage ⭐Until deleted~5 MB per siteNoCart, theme, preferences, drafts
sessionStorageUntil the tab closes~5 MBNoOne-time wizard steps, a tab’s temporary state
CookiesSet by expiry~4 KB eachYes, with every requestLogin sessions (HttpOnly, set by the server)
IndexedDBUntil deletedLarge (hundreds of MB)NoOffline apps, big data, files

The API: strings in, strings out

JavaScript
// Node.js has no localStorage, so this demo creates a tiny stand-in.
// In the browser, delete these 7 lines – localStorage already exists.
const localStorage = (() => {
  const data = new Map();
  return { getItem: k => (data.has(k) ? data.get(k) : null), setItem: (k, v) => data.set(k, String(v)),
           removeItem: k => data.delete(k), clear: () => data.clear(), get length() { return data.size; },
           key: i => [...data.keys()][i] ?? null };
})();

localStorage.setItem('theme', 'dark');
localStorage.setItem('visits', 3);                 // stored as the STRING "3"
console.log(localStorage.getItem('theme'));
console.log(typeof localStorage.getItem('visits'), Number(localStorage.getItem('visits')) + 1);
console.log(localStorage.getItem('missing'));      // null when not found

localStorage.setItem('cart', { id: 1, qty: 2 });   // ❌ objects become "[object Object]"
console.log(localStorage.getItem('cart'));

localStorage.setItem('cart', JSON.stringify([{ id: 1, qty: 2 }]));   // ✅
const cart = JSON.parse(localStorage.getItem('cart'));
console.log(cart[0].qty, Array.isArray(cart));

localStorage.removeItem('theme');
console.log(localStorage.length, 'keys left');
dark string 4 null [object Object] 2 true 2 keys left
⚠️ Storage can throw

Safari private mode, a full quota, disabled cookies or a sandboxed frame make localStorage throw an error. One uncaught error stops your whole script – so always wrap storage access in try…catch.

A safe, reusable storage helper

JavaScript
// Node.js has no localStorage, so this demo creates a tiny stand-in.
// In the browser, delete these 7 lines – localStorage already exists.
const localStorage = (() => {
  const data = new Map();
  return { getItem: k => (data.has(k) ? data.get(k) : null), setItem: (k, v) => data.set(k, String(v)),
           removeItem: k => data.delete(k), clear: () => data.clear(), get length() { return data.size; },
           key: i => [...data.keys()][i] ?? null };
})();

const store = {
  get(key, fallback) {
    try {
      const raw = localStorage.getItem(key);
      return raw === null ? fallback : JSON.parse(raw);
    } catch (err) {
      return fallback;                        // corrupted JSON or storage blocked
    }
  },
  set(key, value) {
    try {
      localStorage.setItem(key, JSON.stringify(value));
      return true;
    } catch (err) {
      return false;                           // quota full or blocked
    }
  },
  remove(key) {
    try { localStorage.removeItem(key); } catch (err) { /* ignore */ }
  },
};

store.set('ss-cart', { version: 2, items: [{ id: 1, qty: 2 }, { id: 4, qty: 1 }] });
console.log(store.get('ss-cart', { version: 2, items: [] }).items.length, 'items');
console.log(store.get('ss-theme', 'light'));            // default when missing
localStorage.setItem('broken', '{not json');
console.log(store.get('broken', 'safe default'));
2 items light safe default

Versioning saved data

JavaScript
// Node.js has no localStorage, so this demo creates a tiny stand-in.
// In the browser, delete these 7 lines – localStorage already exists.
const localStorage = (() => {
  const data = new Map();
  return { getItem: k => (data.has(k) ? data.get(k) : null), setItem: (k, v) => data.set(k, String(v)),
           removeItem: k => data.delete(k), clear: () => data.clear(), get length() { return data.size; },
           key: i => [...data.keys()][i] ?? null };
})();

// Old site (v1) saved: { "1": 2, "4": 1 }  (id → qty)
localStorage.setItem('ss-cart', JSON.stringify({ 1: 2, 4: 1 }));

function loadCart() {
  let saved;
  try { saved = JSON.parse(localStorage.getItem('ss-cart')); } catch (e) { saved = null; }
  if (!saved) return { version: 2, items: [] };
  if (saved.version === 2) return saved;
  // migrate v1 → v2 so returning customers keep their cart
  const items = Object.entries(saved).map(([id, qty]) => ({ id: Number(id), qty }));
  const migrated = { version: 2, items };
  localStorage.setItem('ss-cart', JSON.stringify(migrated));
  return migrated;
}
console.log(JSON.stringify(loadCart()));
{"version":2,"items":[{"id":1,"qty":2},{"id":4,"qty":1}]}
💡 Prefix your keys

Use names like ss-cart, ss-theme. Every script on the same domain shares one localStorage – prefixes avoid clashes with plugins or other apps on subfolders.

Real task: theme + draft autosave

HTML + JavaScript
<button id="theme">🌓 Toggle theme</button>
<p><label for="msg">Message for Sharma Sweets</label><br>
<textarea id="msg" rows="3" cols="40" placeholder="Type – it is saved as you go"></textarea></p>
<p id="status" role="status"></p>

<script>
// safe helpers (same as above, shortened)
const store = {
  get(k, d) { try { const r = localStorage.getItem(k); return r === null ? d : JSON.parse(r); } catch (e) { return d; } },
  set(k, v) { try { localStorage.setItem(k, JSON.stringify(v)); return true; } catch (e) { return false; } },
};
const status = document.querySelector('#status');

// theme
let theme = store.get('ss-theme', 'light');
const apply = () => { document.body.style.background = theme === 'dark' ? '#111827' : '#fff'; document.body.style.color = theme === 'dark' ? '#e5e7eb' : '#111827'; };
apply();
document.querySelector('#theme').addEventListener('click', () => {
  theme = theme === 'dark' ? 'light' : 'dark';
  const saved = store.set('ss-theme', theme);
  apply();
  status.textContent = saved ? 'Theme saved ✅' : 'Theme changed (saving is blocked in this preview – works on a real page)';
});

// draft autosave
const msg = document.querySelector('#msg');
msg.value = store.get('ss-draft', '');
msg.addEventListener('input', () => {
  const ok = store.set('ss-draft', msg.value);
  status.textContent = ok ? 'Draft saved ✓' : 'Draft kept in memory only (storage blocked here)';
});
</script>
▶  On a normal page both survive a reload; in this sandboxed preview the helper falls back gracefully

What you must NEVER store

OK in localStorage

  • Cart items and quantities
  • Theme, language, last filter
  • Form drafts (non-sensitive)
  • Recently viewed products

Never in localStorage

  • Passwords or OTPs
  • Card numbers, UPI PINs, Aadhaar
  • Long-lived login tokens (any script can read them – XSS)
  • Prices used for billing – always recalculate on the server

Bonus: sync between tabs

JavaScript – the storage event
// Fires in OTHER tabs of the same site when localStorage changes
window.addEventListener('storage', (e) => {
  if (e.key === 'ss-cart') {
    cart = JSON.parse(e.newValue || '{"version":2,"items":[]}');
    renderCartBadge();          // the cart count updates in every open tab
  }
});

🏅 Job skills unlocked today

✔ Choose the right browser storage✔ Save and load objects with JSON✔ Write a safe storage helper with defaults and migrations✔ Persist carts, themes and drafts responsibly

Practice tasks

🏋️ Practice – do it yourself

Task 1: Count page visits: read ss-visits (default 0), add 1, save, and print a welcome-back message after the 3rd visit.
Show solution
JavaScript
// Node.js has no localStorage, so this demo creates a tiny stand-in.
// In the browser, delete these 7 lines – localStorage already exists.
const localStorage = (() => {
  const data = new Map();
  return { getItem: k => (data.has(k) ? data.get(k) : null), setItem: (k, v) => data.set(k, String(v)),
           removeItem: k => data.delete(k), clear: () => data.clear(), get length() { return data.size; },
           key: i => [...data.keys()][i] ?? null };
})();

function visit() {
  const n = Number(localStorage.getItem('ss-visits') || 0) + 1;
  localStorage.setItem('ss-visits', n);
  return n >= 3 ? `Welcome back! Visit #${n} – here is 5% off 🎁` : `Visit #${n}`;
}
console.log(visit());
console.log(visit());
console.log(visit());
Visit #1 Visit #2 Welcome back! Visit #3 – here is 5% off 🎁
Task 2: Save “recently viewed” products: keep the last 5 unique ids, newest first.
Show solution
JavaScript
// Node.js has no localStorage, so this demo creates a tiny stand-in.
// In the browser, delete these 7 lines – localStorage already exists.
const localStorage = (() => {
  const data = new Map();
  return { getItem: k => (data.has(k) ? data.get(k) : null), setItem: (k, v) => data.set(k, String(v)),
           removeItem: k => data.delete(k), clear: () => data.clear(), get length() { return data.size; },
           key: i => [...data.keys()][i] ?? null };
})();

function remember(id) {
  let list = JSON.parse(localStorage.getItem('ss-recent') || '[]');
  list = [id, ...list.filter(x => x !== id)].slice(0, 5);
  localStorage.setItem('ss-recent', JSON.stringify(list));
  return list;
}
[3, 1, 4, 1, 5, 9, 2].forEach(id => remember(id));
console.log(JSON.parse(localStorage.getItem('ss-recent')));
[ 2, 9, 5, 1, 4 ]
Task 3: Store the last chosen filter of the Day 8 product filter in sessionStorage so it survives a refresh but not a new tab.

Quick quiz

🧠 Quick Quiz – test yourself

1. localStorage.setItem("n", 5); typeof localStorage.getItem("n") is…
Everything is a string.
2. getItem for a missing key returns…
Check for null.
3. Which is cleared when the tab closes?
Session = tab.
4. Which should never be in localStorage?
Readable by any script.
5. Store an array properly with…
Parse when reading.

Interview corner

💼 Interview Corner

localStorage vs sessionStorage vs cookies?

localStorage persists per origin until cleared; sessionStorage lasts for the tab session; both ~5 MB, synchronous, never sent to the server. Cookies are small, sent with every request, can be HttpOnly/Secure/SameSite – right for server sessions.

Why is storing JWTs in localStorage risky?

Any JavaScript running on the page – including injected XSS code or a compromised third-party script – can read it and send it to an attacker. HttpOnly, Secure, SameSite cookies are not readable by JavaScript.

Summary

  • localStorage persists, sessionStorage per tab; both store strings.
  • JSON.stringify to save objects, JSON.parse to read.
  • Wrap access in try…catch, use defaults, prefixes and versions.
  • Never store secrets; recalculate prices on the server.
➡️ Next

Day 16: scope, hoisting and closures – the concepts interviewers love and that power counters, caches and private data.

Frequently Asked Questions

Where can I see stored data?
DevTools → Application → Local Storage / Session Storage. You can edit and delete keys there while testing.
Is localStorage shared between http and https?
No. Storage belongs to an origin (protocol + domain + port), so http://site and https://site have separate storage.
← JavaScript (30 Days)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicDay 16: Scope, Hoisting & Closures Your progress: 15 / 30 (50%) · Lesson 16 / 30 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free