JSON
When a browser talks to a server, when you save a cart in localStorage, or when two programs written in different languages share data, the data usually travels as JSON. It is plain text that any language can read and write.
In this lesson you will learn the JSON rules, turn JavaScript values into JSON with JSON.stringify(), turn JSON back into values with JSON.parse(), control both directions with replacers, revivers and toJSON(), and see the new ES2026 way to keep very large numbers exact.
What JSON looks like
JSON stands for JavaScript Object Notation. It borrowed its look from JavaScript objects and arrays, but it is a stricter, text-only format:
{
"name": "Meera",
"city": "Jaipur",
"age": 21,
"scholarship": true,
"guardian": null,
"subjects": ["Physics", "Chemistry", "Maths"],
"address": { "pin": "302001", "state": "Rajasthan" }
}The rules are short but strict:
- Keys must be in double quotes. Strings use double quotes too, never single quotes.
- Values can only be strings, numbers,
true,false,null, objects and arrays. - No
undefined, no functions, no dates, noNaNorInfinity. - No comments and no trailing comma after the last item.
A single mistake, such as one trailing comma, makes the whole text invalid.
JSON.stringify: value to text
JSON.stringify(value) turns a value into a JSON string. Pay attention to what happens to values that JSON cannot represent:
const order = {
id: 5012,
customer: "Ananya",
items: ["Paneer roll", "Lassi"],
total: 240,
paid: true,
coupon: null,
note: undefined,
placedAt: new Date(Date.UTC(2026, 9, 29, 6, 30)),
describe() {
return `${this.customer}: ₹${this.total}`;
},
};
console.log(JSON.stringify(order));
console.log(JSON.stringify([undefined, NaN, Infinity]));
console.log(JSON.stringify(new Map([["chai", 20]])));
console.log(JSON.stringify({ city: "Kochi", pin: 682001 }, null, 2));{"id":5012,"customer":"Ananya","items":["Paneer roll","Lassi"],"total":240,"paid":true,"coupon":null,"placedAt":"2026-10-29T06:30:00.000Z"}
[null,null,null]
{}
{
"city": "Kochi",
"pin": 682001
}Notice four things:
- The
noteproperty (undefined) and thedescribemethod disappeared completely. - The date became a string in ISO format. It will not turn back into a date by itself.
- Inside arrays,
undefined,NaNandInfinitybecomenull. - A
Map(and aSet) becomes an empty object, so convert it first, for example withObject.fromEntries(map)or[...set].
The third argument adds indentation. JSON.stringify(value, null, 2) gives readable output with two spaces per level, which is handy for logs and config files.
Choosing what to save: replacers and toJSON
The second argument of JSON.stringify() is a replacer. An array replacer lists the keys to keep. A function replacer is called for every key and value, and whatever it returns is saved instead; returning undefined leaves the key out. An object can also have a toJSON() method, which decides how that object is saved. That is exactly how dates become strings.
const user = {
name: "Kabir",
email: "kabir@example.com",
password: "chai@123",
balance: 1520.4567,
};
// 1. An array replacer keeps only these keys
console.log(JSON.stringify(user, ["name", "email"]));
// 2. A function replacer sees every key and value
const safe = JSON.stringify(user, (key, value) => {
if (key === "password") return undefined; // leave it out
if (typeof value === "number") return Number(value.toFixed(2));
return value;
});
console.log(safe);
// 3. toJSON lets an object decide how it is saved
class Money {
constructor(paise) {
this.paise = paise;
}
toJSON() {
return `₹${(this.paise / 100).toFixed(2)}`;
}
}
console.log(JSON.stringify({ fee: new Money(129900) }));{"name":"Kabir","email":"kabir@example.com"}
{"name":"Kabir","email":"kabir@example.com","balance":1520.46}
{"fee":"₹1299.00"}JSON.parse: text to value
JSON.parse(text) reads a JSON string and builds the matching JavaScript value. If the text breaks any rule, it throws a SyntaxError, so wrap it in try...catch whenever the text comes from outside your code. The optional second argument is a reviver: a function called for every key and value, which can return a replacement. It is the natural place to turn date strings back into Date objects.
const text = '{"name":"Rohan","marks":[78,85,91],"passed":true,"joined":"2025-06-02T04:30:00.000Z"}';
const student = JSON.parse(text);
console.log(student.marks[1] + 5);
console.log(typeof student.joined);
// A reviver runs for every key and can change the value
const revived = JSON.parse(text, (key, value) => {
return key === "joined" ? new Date(value) : value;
});
console.log(revived.joined instanceof Date, revived.joined.getUTCFullYear());
// Invalid JSON throws a SyntaxError
const attempts = ["{'name': 'Rohan'}", '{"name": "Rohan",}', ""];
for (const attempt of attempts) {
try {
JSON.parse(attempt);
} catch (error) {
console.log(`${error.name}: ${attempt || "(empty string)"}`);
}
}90
string
true 2025
SyntaxError: {'name': 'Rohan'}
SyntaxError: {"name": "Rohan",}
SyntaxError: (empty string)The parsed marks are real numbers, so 85 + 5 gives 90. Single quotes, a trailing comma and even an empty string are all invalid JSON. The empty string catches many people: a server that replies with an empty body makes JSON.parse("") throw.
You already used these two functions in localStorage & sessionStorage, and response.json() from the Fetch API is simply JSON.parse() applied to the response body.
Copying objects: structuredClone, not JSON
You may see JSON.parse(JSON.stringify(obj)) used to make a deep copy of an object. It works only for plain data and silently breaks anything else. The built-in structuredClone() is the better choice today:
const original = {
name: "Isha",
joined: new Date(Date.UTC(2025, 0, 15)),
courses: new Set(["html", "js"]),
};
const viaJson = JSON.parse(JSON.stringify(original));
const viaClone = structuredClone(original);
console.log(typeof viaJson.joined, viaJson.courses);
console.log(viaClone.joined instanceof Date, viaClone.courses.has("js"));string {}
true trueThe JSON copy turned the date into a string and emptied the set. structuredClone() kept both. Neither can copy functions or class methods.
Common mistakes
- Parsing something that is already an object.
JSON.parse({ a: 1 })turns the object into the text"[object Object]"and throws aSyntaxError. - Stringifying twice.
JSON.stringify(JSON.stringify(data))gives a string full of escaped quotes. Convert once. - Writing JSON by hand with single quotes or trailing commas. Build the object in JavaScript and let
JSON.stringify()write the text. - Expecting dates to come back as dates. Use a reviver, or store a timestamp number.
- Circular references. An object that refers to itself throws
TypeError: Converting circular structure to JSON.
Key points
- JSON is a strict text format: double-quoted keys and strings, no comments, no trailing commas, no
undefinedor functions. JSON.stringify()dropsundefinedand functions, turns dates into strings, and indents output with its third argument.- Replacers and
toJSON()control what gets saved; revivers control what comes back. JSON.parse()throws aSyntaxErrorfor invalid text, so wrap it intry...catch.- Use
structuredClone()for deep copies instead of a JSON round trip. - ES2026 gives revivers the original source text, so large numbers can be kept exact.
Exercise
Create an object for a cricket match with teams (an array of two names), venue, date (a Date) and a secretScorerPin. Convert it to pretty JSON with two-space indentation, leaving out secretScorerPin. Then parse the text back with a reviver so that date becomes a real Date again, and log the year using getUTCFullYear().
Show solution
const match = {
teams: ["Rohtak Royals", "Jaipur Jaguars"],
venue: "Lucknow",
date: new Date(Date.UTC(2026, 10, 14)),
secretScorerPin: "4471",
};
const json = JSON.stringify(
match,
(key, value) => (key === "secretScorerPin" ? undefined : value),
2
);
console.log(json);
const back = JSON.parse(json, (key, value) => (key === "date" ? new Date(value) : value));
console.log(back.date.getUTCFullYear()); // 2026The replacer returns undefined for the PIN, so that key is left out. The reviver rebuilds the date from its ISO string.
Quick Quiz
1. Which of these is valid JSON?
JSON needs double quotes and does not allow a trailing comma.
2. What does JSON.stringify({ a: 1, b: undefined }) return?
Properties whose value is undefined are left out of objects completely.
3. What happens when JSON.parse() receives invalid text?
Invalid JSON always throws, so wrap JSON.parse() in try...catch for untrusted text.
4. What is the best way to deep-copy an object that contains a Date and a Set?
structuredClone keeps dates, sets and maps; the JSON round trip turns them into strings and empty objects.
Learn JavaScript with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
