What is JSON, and why does it look like JavaScript?
JSON stands for JavaScript Object Notation. It is a text format for describing data: a string of characters that spells out objects, arrays, numbers, text, true, false and null. Because it is only text, it can be saved in a file, stored in localStorage, sent across the internet and read by programs written in any language.
The syntax was borrowed from JavaScript object literals, which is why it looks familiar. The difference is what you are holding. A JavaScript object is a live value in memory: you can read order.qty, add 1 to it and pass it to a function. JSON is a string. Until you parse it, text.qty is undefined, because strings do not have a qty property.
Almost every web API answers in JSON. When the bird club page asks a server for today's sightings, the reply arrives as JSON text, and your code turns it into objects before using it. When the page saves a to-do list in localStorage, it has to turn the list into JSON first, because storage only keeps strings.
const order = { item: "Rye loaf", qty: 2 };
const text = JSON.stringify(order);
console.log(typeof order); // object
console.log(typeof text); // string
console.log(text); // {"item":"Rye loaf","qty":2}

JSON.stringify writes the text; JSON.parse reads it and builds a brand new object.What rules does JSON text follow?
JSON is stricter than JavaScript. Data written by hand or by an AI tool often breaks one of these rules, and the parser refuses the whole thing when it does.
Writing the text yourself is rare. Most of the time JSON.stringify writes it and the rules take care of themselves. The rules matter when you paste JSON into code, edit a config file, or read an error message about a file someone else wrote.
{
"club": "Hilltop Birders",
"members": 42,
"active": true,
"walks": ["Saturday", "Wednesday"],
"leader": null
}- Keys must be in double quotes:
{"name": "Ada"}. Bare keys like{name: "Ada"}are JavaScript, and they are invalid JSON. - Strings use double quotes only. Single quotes and backticks are rejected.
- No trailing comma after the last item in an object or array.
- No comments. A
//line in a JSON file makes it invalid. - Values are limited to strings, numbers,
true,false,null, objects and arrays. There is noundefined, no functions, no dates and noNaNorInfinity. - Numbers are plain decimals: no leading zeros like
007, no hex like0xff.
How do you turn a value into JSON text?
JSON.stringify(value) returns a string. By default it packs everything onto one line with no spaces, which is the right shape for saving or sending because it is small.
For reading with your own eyes, pass a third argument: the number of spaces to indent each level. JSON.stringify(order, null, 2) puts each key on its own line, indented by two spaces per level. The second argument, null here, is a replacer that can filter or change values; you will rarely need it, so pass null to skip it.
Logging an object with console.log(order) already shows it nicely in the Console panel, so you do not need stringify for that. Use it when you need the text itself: to put it in a <pre> element, to store it, or to compare two objects by their contents in a quick test.
const walk = { day: "Saturday", birds: ["Wren", "Jay"] };
console.log(JSON.stringify(walk));
console.log(JSON.stringify(walk, null, 2));What does JSON.stringify leave out or change?
Some JavaScript values have no JSON form, and JSON.stringify handles them without any warning. Properties whose value is undefined or a function disappear from objects. Inside arrays they become null, so the positions still line up. NaN and Infinity also become null.
Dates are turned into strings in ISO format, such as "2026-03-14T09:30:00.000Z". Parsing that text later gives you a string back, not a Date. To use date methods again, wrap it: new Date(order.pickup). Maps and Sets become {}, which loses all their contents, so convert them to arrays or objects first.
This quiet behaviour is a common source of lost data. A recipe object with a scale() method saves fine, loads fine and is missing the method. If you rely on a value, check what the saved text looks like by logging it once.
const loaf = {
name: "Spelt",
baked: new Date("2026-03-14T06:00:00Z"),
note: undefined,
slice() { return "sliced"; }
};
console.log(JSON.stringify(loaf));
// {"name":"Spelt","baked":"2026-03-14T06:00:00.000Z"}How do you read JSON text back into a value?
JSON.parse(text) reads a JSON string and returns a fresh value built from it. A JSON object becomes a plain JavaScript object, an array becomes an array, and the rest map across as you would expect.
The new value has no link to the one you stringified. Changing the parsed copy does not touch the original, and the parsed object is a plain object even if the original was something fancier.
Use the Step lens on the example below and watch menu appear in the variable panel as a real array once the parse line has run. Before that line, there is only the string.
const text = '[{"name":"Rye","price":4.5},{"name":"Spelt","price":5}]';
const menu = JSON.parse(text);
console.log(menu.length); // 2
console.log(menu[1].name); // SpeltWhat happens when the JSON is broken?
If the text is not valid JSON, JSON.parse throws a SyntaxError and your script stops at that line. Chrome's message reads like Unexpected token ' in JSON at position 1 or is not valid JSON, and the position number counts characters from the start of the text, which helps you find the bad spot.
Data from outside your code can always be broken: a half-written file, an old format, a value someone edited by hand in localStorage, or an error page returned as HTML when you expected JSON. Wrap those parses in try...catch, and decide what the page should do instead, such as starting with an empty list.
Keep the try block small. Put only the parse inside it, so a mistake elsewhere in your code is not silently swallowed by the same catch. Also check for null: JSON.parse(null) returns null without throwing, which happens when localStorage.getItem finds nothing.
const saved = "{'qty': 2}";
let order;
try {
order = JSON.parse(saved);
} catch (error) {
console.log("Saved order was unreadable:", error.message);
order = { qty: 0 };
}
console.log(order.qty);How do you copy an object without JSON tricks?
Older code copies objects with JSON.parse(JSON.stringify(obj)). It works for simple data and fails on everything listed above: dates become strings, undefined values vanish, Maps empty out.
Use structuredClone(obj) instead. It makes a deep copy, meaning nested objects and arrays are copied too, and it keeps dates as dates, Maps as Maps and Sets as Sets. It has been in every major browser since 2022. It throws on functions and DOM elements, which is honest: it tells you up front that it cannot copy them.
A shallow copy with spread, { ...order }, is enough when the object has no nested objects you plan to change. When you see the JSON round trip in AI-written code, ask whether structuredClone or spread would be clearer.
const plan = { day: "Sat", start: new Date("2026-03-14T08:00:00Z"), birds: ["Wren"] };
const copy = structuredClone(plan);
copy.birds.push("Jay");
console.log(plan.birds.length); // 1
console.log(copy.start instanceof Date); // trueWhat does JSON from a server look like?
A later lesson covers fetch, the function that asks a server for data. Here is the shape of it so the JSON part is familiar when you get there. The server sends text. response.json() reads that text and runs the same parsing step as JSON.parse, giving you objects and arrays.
The practice server in this editor answers /api/bakery/menu with JSON. Errors there behave the same way as here: if the server sends an HTML error page instead of JSON, parsing fails with a message about an unexpected <, because HTML starts with < and JSON never does.
When reading AI-written code that handles JSON, check three things: that parses of outside data are inside try...catch, that dates are turned back into Date objects after loading, and that nobody builds JSON by gluing strings together with +, which breaks the moment a value contains a quote mark.
// Preview of the fetch lesson
fetch("/api/bakery/menu")
.then((response) => response.json())
.then((menu) => console.log(menu));Field notes
- JSON is a text format for data that looks like JavaScript objects and arrays.
- JSON is stricter than JavaScript, with double quotes and no trailing commas.
JSON.stringifyturns a value into text, and a third argument adds indentation.JSON.parsereads JSON text and throws a SyntaxError if it is broken.
Easy to get wrong
JSON needs double quotes around keys and strings. JavaScript object syntax is looser, so text copied from code often fails to parse.
A date comes back from JSON as a string, and the saved value may be missing entirely. Convert the string with new Date() and handle null.
The JSON round trip turns dates into strings and drops undefined values. structuredClone keeps them.
Gluing strings breaks as soon as name contains a double quote or a backslash. JSON.stringify escapes those for you.
Questions people ask
Is JSON the same as a JavaScript object?
No. JSON is text that describes data, and an object is a value in memory. They look alike because JSON copied the object literal syntax, with stricter rules.
Why does JSON.stringify give me an empty object for a Map?
A Map stores its entries outside normal properties, and JSON.stringify only reads properties. Convert it first with Object.fromEntries(map) or [...map].
Can JSON files have comments?
Standard JSON cannot. Some tools accept variants with comments for config files, but JSON.parse in the browser rejects them.
Does the indentation change the data?
No. Spaces and line breaks between values are ignored by JSON.parse. Indented and compact JSON parse to the same value.
What is the .json file extension for?
It marks a file holding JSON text, and servers send it with the content type application/json. The contents follow the same rules as any JSON string.