AiTechWorlds
A
AiTechWorlds
JSON (JavaScript Object Notation) is the universal format for data exchange on the web. Every API you call sends and receives JSON. Understanding it deeply including its quirks and limitations is non negotiable for web development.
JSON looks like JavaScript objects but has stricter rules:
{
"name": "Alice",
"age": 30,
"active": true,
"scores": [95, 87, 92],
"address": {
"city": "New York",
"zip": "10001"
},
"notes": null
}JSON rules:
const user = { name: "Alice", age: 30, active: true };
JSON.stringify(user);
// '{"name":"Alice","age":30,"active":true}'
// Pretty-print (3rd argument is indent spaces)
JSON.stringify(user, null, 2);
// {
// "name": "Alice",
// "age": 30,
// "active": true
// }
// What gets dropped:
const messy = {
name: "Alice",
fn: () => "hello", // ← dropped (functions)
undef: undefined, // ← dropped (undefined)
sym: Symbol("id"), // ← dropped (symbols)
date: new Date(), // ← converted to ISO string
num: Infinity, // ← becomes null
nan: NaN // ← becomes null
};
JSON.stringify(messy, null, 2);
// { "name": "Alice", "date": "2026-05-26T...", "num": null, "nan": null }// Only include specific keys
JSON.stringify(user, ["name", "active"]);
// '{"name":"Alice","active":true}'
// Transform values during serialization
const data = { name: "Alice", password: "secret123", age: 30 };
JSON.stringify(data, (key, value) => {
if (key === "password") return undefined; // omit
return value;
});
// '{"name":"Alice","age":30}'Objects can define how they serialize themselves:
class User {
constructor(name, password) {
this.name = name;
this.password = password;
}
toJSON() {
// Only expose safe fields
return { name: this.name };
}
}
JSON.stringify(new User("Alice", "secret"));
// '{"name":"Alice"}'const json = '{"name":"Alice","age":30,"scores":[95,87]}';
const user = JSON.parse(json);
user.name; // "Alice"
user.scores[0]; // 95
// With reviver function — transform values during parsing
const dateJson = '{"name":"Alice","createdAt":"2026-01-15T10:30:00.000Z"}';
const parsed = JSON.parse(dateJson, (key, value) => {
if (key === "createdAt") return new Date(value); // convert to Date object
return value;
});
parsed.createdAt instanceof Date; // true
parsed.createdAt.getFullYear(); // 2026JSON.parse throws on invalid JSON. Always wrap it:
function safeParseJSON(str, fallback = null) {
try {
return JSON.parse(str);
} catch {
return fallback;
}
}
safeParseJSON('{"valid": true}'); // { valid: true }
safeParseJSON('not json at all'); // null
safeParseJSON('undefined', {}); // {}
// In practice — API responses
async function fetchUser(id) {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) {
const errorText = await res.text();
const error = safeParseJSON(errorText, { message: errorText });
throw new Error(error.message ?? "Request failed");
}
return res.json(); // fetch's .json() already parses + throws on bad JSON
}// GET request — receive JSON
const response = await fetch("https://api.example.com/users");
const users = await response.json(); // parses JSON automatically
// POST request — send JSON
const newUser = { name: "Alice", email: "alice@example.com" };
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
},
body: JSON.stringify(newUser) // serialize before sending
});
const created = await response.json();
console.log(created.id); // the ID assigned by the serverlocalStorage only stores strings, so JSON is used to serialize/deserialize:
// Save
const cart = [{ id: 1, qty: 2 }, { id: 3, qty: 1 }];
localStorage.setItem("cart", JSON.stringify(cart));
// Load
const saved = localStorage.getItem("cart");
const cart = saved ? JSON.parse(saved) : [];
// Utility wrapper
const storage = {
get(key, fallback = null) {
return safeParseJSON(localStorage.getItem(key), fallback);
},
set(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
remove(key) {
localStorage.removeItem(key);
}
};
storage.set("preferences", { theme: "dark", language: "en" });
storage.get("preferences"); // { theme: "dark", language: "en" }A quick way to deep clone objects but with limitations:
// Works for: strings, numbers, booleans, arrays, plain objects
const original = { a: 1, b: { c: 2 }, d: [3, 4] };
const clone = JSON.parse(JSON.stringify(original));
clone.b.c = 99;
original.b.c; // 2 — unaffected
// Does NOT work for: Dates, functions, undefined, circular references
const withDate = { date: new Date(), fn: () => {} };
JSON.parse(JSON.stringify(withDate));
// { date: "2026-05-26T..." } — Date becomes string, fn is dropped!
// Better alternatives:
// structuredClone (built-in, handles more types)
const clone2 = structuredClone(original);
// lodash deepClone
import cloneDeep from "lodash/cloneDeep";
const clone3 = cloneDeep(withDate); // preserves Dates, handles circular refsNext lesson: DOM Manipulation selecting and modifying HTML elements from JavaScript.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises