Working with JSON in JavaScript
JSON is JavaScript's native data format. Every modern browser has JSON.parse() and JSON.stringify() built in, and the fetch API returns JSON by default. Mastering these four patterns covers 90 percent of real-world JSON work in JavaScript.
JSON.parse() — String to Object
JSON.parse() takes a JSON string and returns a JavaScript value — object, array, number, string, boolean, or null.
const json = '{"name": "Ravi", "age": 28, "active": true}';
const obj = JSON.parse(json);
console.log(obj.name); // "Ravi"
console.log(obj.age); // 28
console.log(obj.active); // trueAlways wrap JSON.parse() in try/catch. Invalid JSON throws a SyntaxError that will crash your application if unhandled:
function safeParseJSON(str) {
try {
return { data: JSON.parse(str), error: null };
} catch (e) {
return { data: null, error: e.message };
}
}
const { data, error } = safeParseJSON(rawString);
if (error) console.error("Parse failed:", error);JSON.stringify() — Object to String
JSON.stringify() converts a JavaScript value to a JSON string.
const user = { name: "Ravi", age: 28, city: "Surat" };
const json = JSON.stringify(user);
// '{"name":"Ravi","age":28,"city":"Surat"}'Add the third argument for pretty-printing with indentation:
const pretty = JSON.stringify(user, null, 2);
// {
// "name": "Ravi",
// "age": 28,
// "city": "Surat"
// }What JSON.stringify() Silently Drops
These JavaScript values are not part of JSON and are handled automatically — sometimes in surprising ways:
const obj = {
a: 1,
b: undefined, // dropped entirely
c: function() {}, // dropped entirely
d: Symbol("x"), // dropped entirely
e: NaN, // becomes null
f: Infinity, // becomes null
};
JSON.stringify(obj);
// '{"a":1,"e":null,"f":null}'If you need to preserve undefined values, convert them to null before stringifying.
The replacer Argument — Filter or Transform Keys
Pass an array of key names to include only those keys in the output:
const user = { id: 1, name: "Ravi", password: "secret", role: "admin" };
JSON.stringify(user, ["id", "name", "role"]);
// '{"id":1,"name":"Ravi","role":"admin"}'Pass a function for custom control over each value:
JSON.stringify(user, (key, value) => {
if (key === "password") return undefined; // exclude
if (typeof value === "string") return value.trim(); // transform
return value;
});The reviver Argument — Transform While Parsing
The reviver function in JSON.parse() runs on every key-value pair while the JSON is being parsed. This is the correct way to restore Date objects:
const json = '{"name":"Ravi","createdAt":"2025-01-15T10:30:00Z"}';
const obj = JSON.parse(json, (key, value) => {
if (key === "createdAt") return new Date(value);
return value;
});
console.log(obj.createdAt instanceof Date); // true
console.log(obj.createdAt.getFullYear()); // 2025Fetch API with JSON — GET Request
The fetch API has a built-in .json() method that calls JSON.parse() for you:
async function getUser(id) {
const response = await fetch(`https://api.example.com/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json(); // parses JSON automatically
}
const user = await getUser(1);
console.log(user.name);Always check response.ok before calling .json(). A 404 or 500 response has a body too — it is just an error body.
Fetch API with JSON — POST Request
When sending JSON in a POST request, set the Content-Type header and stringify the body:
async function createUser(userData) {
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + getToken(),
},
body: JSON.stringify(userData),
});
if (!response.ok) {
const err = await response.json();
throw new Error(err.message ?? "Request failed");
}
return response.json();
}
const newUser = await createUser({ name: "Ravi", email: "ravi@example.com" });Without Content-Type: application/json, the server may not parse the request body correctly.
localStorage with JSON
localStorage only stores strings. Serialize with JSON.stringify when saving and parse with JSON.parse when loading:
// Save an object
const settings = { theme: "dark", fontSize: 14, lang: "en" };
localStorage.setItem("settings", JSON.stringify(settings));
// Load it back
const raw = localStorage.getItem("settings");
const settings = raw ? JSON.parse(raw) : { theme: "light", fontSize: 14, lang: "en" };Always provide a fallback value — the key may not exist if the user has never saved settings.
Deep Clone with JSON
A quick way to deep-clone a plain object is to stringify then parse it:
const original = { user: { name: "Ravi", tags: ["a", "b"] } };
const clone = JSON.parse(JSON.stringify(original));
clone.user.name = "Priya";
console.log(original.user.name); // "Ravi" — not affectedLimitation: this only works for values that survive JSON serialization — strings, numbers, booleans, null, plain objects, and arrays. It does not work with Date, Map, Set, Functions, or undefined. For those, use structuredClone() (available in all modern browsers and Node.js 17+).
Handling Dates in JSON
JSON has no Date type. Dates are serialised as ISO 8601 strings. Always store and transmit dates in this format:
// Serialise
const event = { title: "Launch", date: new Date().toISOString() };
const json = JSON.stringify(event);
// '{"title":"Launch","date":"2025-05-01T10:30:00.000Z"}'
// Deserialise
const parsed = JSON.parse(json);
const date = new Date(parsed.date); // restore as Date object
console.log(date.getFullYear()); // 2025Format JSON for Debugging
You do not always want to minify JSON when logging. Use JSON.stringify with indent=2 to get readable debug output:
console.log(JSON.stringify(apiResponse, null, 2));Or paste the response into JSONKit's formatter at /json-formatter for interactive exploration with collapsible tree view and syntax highlighting.