Convert data to text with JSON and save it in the browser so it survives a page refresh.

Bishal Biswas
Self Learner
What is JSON?
JSON stands for JavaScript Object Notation. It is a text format for data, and it is what almost every API on the internet speaks.
// A JavaScript object
const user = { name: 'Asha', age: 28, active: true };
// The same thing as JSON text
// {"name":"Asha","age":28,"active":true}
It looks like a JavaScript object, but it is a string. That is the key difference.
JSON rules
JSON is stricter than JavaScript:
- Keys must be in double quotes.
- Strings must use double quotes, never single.
- No trailing commas.
- No comments.
- No functions, no
undefined, no dates.
// Valid JSON
// { "name": "Asha", "tags": ["a", "b"], "age": 28, "active": true, "note": null }
// Invalid JSON
// { name: 'Asha', }
JSON.stringify
Turns a JavaScript value into a JSON string.
const user = { name: 'Asha', age: 28, active: true };
const text = JSON.stringify(user);
console.log(text);
console.log(typeof text);
Pretty printing
console.log(JSON.stringify(user, null, 2));
The third argument is how many spaces to indent by. Useful for logs and files, wasteful for network requests.
What gets dropped
const messy = {
name: 'Asha',
greet: function () { return 'hi'; },
nothing: undefined,
when: new Date(),
ok: true
};
console.log(JSON.stringify(messy));
Functions and undefined vanish silently. Dates become strings, and they do not turn back into dates automatically.
Picking fields
const user = { name: 'Asha', age: 28, password: 'secret' };
console.log(JSON.stringify(user, ['name', 'age']));
JSON.parse
Turns JSON text back into a JavaScript value.
const text = '{"name":"Asha","age":28}';
const user = JSON.parse(text);
console.log(user.name, user.age);
console.log(typeof user);
Always wrap it in try-catch
function safeParse(text, fallback = null) {
try {
return JSON.parse(text);
} catch (error) {
console.warn('Invalid JSON:', error.message);
return fallback;
}
}
console.log(safeParse('{"a":1}'));
console.log(safeParse('not json', {}));
Bad JSON throws a SyntaxError, and that will break your page if you do not catch it.
Deep copying with JSON
A quick trick you will see often:
const original = { name: 'Asha', address: { city: 'Pune' } };
const copy = JSON.parse(JSON.stringify(original));
copy.address.city = 'Delhi';
console.log(original.address.city);
It works, but it loses functions, dates and undefined. Modern code should use structuredClone:
const copy = structuredClone(original);
localStorage
The browser gives every site a small key value store that survives refreshes and even closing the browser.
localStorage.setItem('username', 'asha');
console.log(localStorage.getItem('username'));
localStorage.removeItem('username');
localStorage.clear();
It only stores strings
localStorage.setItem('age', 28);
const age = localStorage.getItem('age');
console.log(age, typeof age);
You get back '28' as text. For objects you must convert:
const settings = { theme: 'dark', fontSize: 16 };
localStorage.setItem('settings', JSON.stringify(settings));
const saved = JSON.parse(localStorage.getItem('settings'));
console.log(saved.theme);
This is why JSON and localStorage are taught together.
Missing keys give null
const value = localStorage.getItem('doesNotExist');
console.log(value);
console.log(JSON.parse(value));
JSON.parse(null) gives null rather than throwing, but a missing key with a partially written value will throw. Always guard:
function loadSettings() {
try {
const raw = localStorage.getItem('settings');
return raw ? JSON.parse(raw) : { theme: 'light' };
} catch {
return { theme: 'light' };
}
}
console.log(loadSettings());
A small storage helper
const storage = {
save(key, value) {
try {
localStorage.setItem(key, JSON.stringify(value));
return true;
} catch (error) {
console.warn('Could not save:', error.message);
return false;
}
},
load(key, fallback = null) {
try {
const raw = localStorage.getItem(key);
return raw === null ? fallback : JSON.parse(raw);
} catch {
return fallback;
}
},
remove(key) {
localStorage.removeItem(key);
}
};
storage.save('cart', [{ name: 'Pen', qty: 2 }]);
console.log(storage.load('cart', []));
Limits and warnings
- About 5 to 10 MB per site. Exceeding it throws a
QuotaExceededError, which is why the helper above uses try-catch. - Synchronous. Reading a large value blocks the page, so keep stored data small.
- Never store secrets. Any script on your page can read localStorage, so no tokens, passwords or personal data.
- Private browsing may block it entirely, so always have a fallback.
Quick recap
- JSON is text, not an object, and its rules are stricter than JavaScript.
JSON.stringifyconverts to text,JSON.parseconverts back.- Functions and
undefinedare dropped, dates become plain strings. - Always wrap
JSON.parsein try-catch. localStoragestores strings only, so stringify objects before saving.- A missing key returns
null. - Keep stored data small and never store anything secret.
// JSON.stringify turns data into text
const user = { name: 'Asha', age: 28, active: true };
const text = JSON.stringify(user);
console.log(text, typeof text); // {"name":"Asha",...} string
console.log(JSON.stringify(user, null, 2)); // pretty printed
// Functions, undefined and dates do not survive the trip
const messy = { name: 'Asha', greet() {}, nothing: undefined, when: new Date() };
console.log(JSON.stringify(messy)); // greet and nothing are gone
// JSON.parse turns text back into data, but it can throw
function safeParse(text, fallback = null) {
try {
return JSON.parse(text);
} catch (error) {
console.warn('Invalid JSON:', error.message);
return fallback;
}
}
console.log(safeParse('{"a":1}'));
console.log(safeParse('not json', {}));
// localStorage only stores strings
localStorage.setItem('age', 28);
console.log(typeof localStorage.getItem('age')); // 'string'
// So objects must be converted both ways
const settings = { theme: 'dark', fontSize: 16 };
localStorage.setItem('settings', JSON.stringify(settings));
console.log(JSON.parse(localStorage.getItem('settings')).theme); // dark
// A safe helper that handles missing keys and quota errors
const storage = {
save(key, value) {
try {
localStorage.setItem(key, JSON.stringify(value));
return true;
} catch (error) {
console.warn('Could not save:', error.message);
return false;
}
},
load(key, fallback = null) {
try {
const raw = localStorage.getItem(key);
return raw === null ? fallback : JSON.parse(raw);
} catch {
return fallback;
}
},
remove(key) { localStorage.removeItem(key); }
};
storage.save('cart', [{ name: 'Pen', qty: 2 }]);
console.log(storage.load('cart', []));
console.log(storage.load('missing-key', 'default value'));
Was this explanation helpful?
Your feedback helps us improve the content for everyone.
Thank you for your feedback!
We appreciate you helping us improve.
What could we improve? (Optional)
Read aloud
Ready