Running Code Locally
While this online editor runs real JavaScript, some advanced examples may have limitations. For the best experience: Download Node.js to run JavaScript on your computer, use your browser's Developer Console (Press F12) to test code snippets, or create a .html file with <script> tags and open it in your browser.
Deep Dive into JSON, Parsing & Serialization
Master JSON handling: serialization, parsing, type preservation, circular references, validation, and production patterns.
What You'll Learn
- JSON stringify & parse
- Custom replacers & revivers
- Handling circular references
- Class serialization with type markers
- Schema validation
- JSON versioning & migrations
📦 Real-World Analogy: Universal Shipping Label
Think of JSON like a **universal shipping label**. When you send a package internationally, you need a label that everyone can read — regardless of what language they speak or what postal system they use. JSON is that universal label for data: it's a simple, text-based format that any programming language can read and write.
📋 JSON Data Types Quick Reference:
| Type | JSON Example | Notes |
|---|---|---|
| String | "hello" | Must use double quotes |
| Number | 42, 3.14 | No NaN or Infinity |
| Boolean | true, false | Lowercase only |
| Null | null | undefined becomes null |
| Array | [1, 2, 3] | Ordered list |
| Object | {"key": "value"} | Keys must be strings |
What JSON Actually Is (And What It Cannot Represent)
JSON (JavaScript Object Notation) is a text-based data format, not JavaScript itself. It has strict rules and can only represent: objects, arrays, strings, numbers, booleans, and null.
JSON Cannot Represent
undefined- gets removed entirely- Functions - removed entirely
- Dates - converted to ISO strings
NaN/Infinity- become null- RegExp, Map, Set - become empty objects
- Circular references - throws error
JSON Data Types
What JSON can and cannot represent
// What JSON can represent
const validData = {
string: "Hello",
number: 42,
boolean: true,
null: null,
array: [1, 2, 3],
object: { nested: "value" }
};
console.log(JSON.stringify(validData, null, 2));
// What JSON CANNOT represent (these get lost or converted)
const problematicData = {
undefined: undefined, // ❌ Removed entirely
function: function() {}, // ❌ Removed entirely
date: new Date(), // ⚠️ Becomes ISO string
nan: NaN, // ⚠️
...JSON.stringify — Serialization
Serialization converts JavaScript values into JSON text. Understanding how different types are handled is crucial to avoiding data loss.
JSON.stringify — Serialization
Convert JavaScript values into JSON text
// Basic serialization
const user = { name: "Boopie", age: 25 };
const json = JSON.stringify(user);
console.log(json);
console.log(typeof json); // "string"
// Pretty-printing with indentation
console.log("\nPretty-printed:");
console.log(JSON.stringify(user, null, 2));
// Date conversion (becomes ISO string)
const withDate = { created: new Date() };
console.log("\nDate becomes string:");
console.log(JSON.stringify(withDate));
// NaN and Infinity become null
const special = { nan: NaN, inf: I
...JSON.parse — Deserialization
Parsing converts JSON text back to JavaScript values. JSON syntax is extremely strict — errors that JavaScript allows will crash JSON.parse.
JSON.parse — Deserialization
Convert JSON text back to JavaScript values
// Basic parsing
const jsonText = '{"name":"Boopie","score":100}';
const obj = JSON.parse(jsonText);
console.log(obj.name); // "Boopie"
console.log(obj.score); // 100
// STRICT syntax rules - these will FAIL:
try {
// Keys must be double-quoted
JSON.parse("{name: 'value'}");
} catch (e) {
console.log("Error 1:", e.message);
}
try {
// Strings must use double quotes, not single
JSON.parse('{"name": \'value\'}');
} catch (e) {
console.log("Error 2:", e.message);
}
try {
// No tra
...Custom Serialization with Replacers
The replacer parameter in JSON.stringify lets you filter keys, transform values, mask sensitive data, and preserve type information.
Custom Replacer Functions
Filter keys, transform values, and mask sensitive data
// Replacer as array - filter specific keys only
const user = {
id: 1,
name: "Boopie",
password: "secret123",
email: "boopie@test.com"
};
// Only include safe fields
const safeJson = JSON.stringify(user, ["id", "name", "email"]);
console.log("Filtered:", safeJson);
// Replacer as function - transform values
const data = {
name: "Boopie",
password: "secret123",
createdAt: new Date(),
balance: 1234.567
};
const transformed = JSON.stringify(data, (key, value) => {
// Mask sensi
...Custom Parsing with Revivers
The reviver parameter in JSON.parse lets you restore Dates, class instances, and other types that JSON destroys during serialization.
Custom Reviver Functions
Restore Dates, class instances, and other types
// Reviver function to restore types
const jsonWithDate = '{"name":"Boopie","created":{"__type":"Date","value":"2025-01-15T10:30:00.000Z"}}';
const restored = JSON.parse(jsonWithDate, (key, value) => {
// Restore Date objects
if (value && value.__type === "Date") {
return new Date(value.value);
}
return value;
});
console.log("Name:", restored.name);
console.log("Created type:", restored.created.constructor.name);
console.log("Is Date?", restored.created instanceof Date);
console.l
...Handling Circular References
Circular references (objects referencing themselves) crash JSON.stringify. You need a custom serializer to handle them safely.
Handling Circular References
Safely serialize objects with circular references
// Circular references break JSON.stringify
const obj = { name: "Parent" };
obj.self = obj; // Circular!
try {
JSON.stringify(obj);
} catch (e) {
console.log("Error:", e.message);
}
// Safe stringify that handles circular references
function safeStringify(obj, space = 2) {
const seen = new WeakSet();
return JSON.stringify(obj, (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return "[Circular Reference]";
}
see
...Serializing Class Instances
When you serialize class instances, all methods are lost. Here's how to preserve and restore class types through JSON.
Serializing Class Instances
Preserve and restore class types through JSON
// Classes lose their methods when serialized
class User {
constructor(name, role) {
this.name = name;
this.role = role;
}
greet() {
return `Hello, I'm ${this.name}`;
}
isAdmin() {
return this.role === "admin";
}
}
const user = new User("Boopie", "admin");
console.log("Before serialize:");
console.log("greet():", user.greet());
console.log("isAdmin():", user.isAdmin());
// After JSON round-trip, methods are GONE
const json = JSON.stringify(user);
const parsed
...JSON Schema Validation
Never trust incoming JSON blindly. Always validate the structure, types, and required fields before using data in your application.
JSON Schema Validation
Validate structure, types, and required fields
// Manual schema validation (without external libraries)
function validateUserSchema(data) {
const errors = [];
if (typeof data !== "object" || data === null) {
return { valid: false, errors: ["Must be an object"] };
}
// Required fields
if (typeof data.id !== "number") {
errors.push("id must be a number");
}
if (typeof data.name !== "string" || data.name.length === 0) {
errors.push("name must be a non-empty string");
}
if (typeof data.email !== "string" || !d
...JSON Transform Pipeline
Professional applications use pipelines to process JSON: safe parse → validate → transform → normalize. This pattern keeps data handling consistent and safe.
JSON Transform Pipeline
Parse → validate → transform → normalize patterns
// Professional JSON processing pipeline
class JSONPipeline {
constructor() {
this.transformers = [];
}
addTransformer(fn) {
this.transformers.push(fn);
return this; // chainable
}
process(json) {
// Step 1: Safe parse
let data;
try {
data = JSON.parse(json);
} catch (e) {
return { success: false, error: "Parse failed: " + e.message };
}
// Step 2: Run transformers
try {
for (const transform of this.transformers) {
...JSON Versioning & Migrations
As your data schema evolves, you need a migration strategy to upgrade old JSON to new formats without breaking existing data.
JSON Versioning & Migrations
Upgrade old JSON formats without breaking data
// JSON versioning for backward compatibility
const migrations = {
// v1 -> v2: renamed 'username' to 'name'
1: (data) => ({
...data,
version: 2,
name: data.username,
username: undefined
}),
// v2 -> v3: nested profile object
2: (data) => ({
version: 3,
profile: {
name: data.name,
email: data.email
},
settings: data.settings || {}
})
};
function migrateToLatest(data) {
const LATEST_VERSION = 3;
let current = { ...data };
// Def
...Safe JSON Storage (localStorage)
Storing JSON in localStorage requires error handling, expiration support, and protection against corrupted data.
Safe JSON Storage
localStorage with error handling and expiration
// Safe localStorage with JSON
const storage = {
set(key, value, ttl = null) {
const item = {
value,
timestamp: Date.now(),
expires: ttl ? Date.now() + ttl : null
};
try {
localStorage.setItem(key, JSON.stringify(item));
return true;
} catch (e) {
console.error("Storage error:", e.message);
return false;
}
},
get(key) {
try {
const raw = localStorage.getItem(key);
if (!raw) return null;
const item
...Deep Cloning with JSON
The JSON.parse(JSON.stringify(obj)) pattern creates deep clones, but has significant limitations. Know when to use it and when to use structuredClone.
Deep Cloning with JSON
Understand limitations of JSON cloning
// JSON cloning - simple but has limitations
const original = {
name: "Boopie",
scores: [100, 95, 88],
settings: { theme: "dark" }
};
// JSON clone method
const jsonClone = JSON.parse(JSON.stringify(original));
// Modify clone - original is safe
jsonClone.scores.push(75);
jsonClone.settings.theme = "light";
console.log("Original scores:", original.scores);
console.log("Clone scores:", jsonClone.scores);
console.log("Original theme:", original.settings.theme);
console.log("Clone theme:",
...JSON Best Practices
✅ DO
- Always wrap parse in try/catch
- Validate JSON structure before use
- Use replacers to preserve type info
- Use revivers to restore types
- Handle circular references safely
- Version your JSON schemas
- Use UTF-8 encoding
- Create transform pipelines
❌ DON'T
- Use eval() to parse JSON
- Assume API data is valid
- Store Dates without restoration plan
- Ignore type loss (undefined, functions)
- Mutate parsed JSON directly
- Use JSON for binary data
- Skip schema validation
- Ignore circular reference errors
🎯 Mastery Summary
- JSON is a strict text format — not all JS types survive serialization
JSON.stringifyconverts to text;JSON.parseconverts back- Use replacers to filter/transform during serialization
- Use revivers to restore types during parsing
- Handle circular references with WeakSet tracking
- Preserve class instances with type markers
- Always validate incoming JSON before using it
- Build transform pipelines for consistent processing
- Version your schemas and create migrations
- Use
structuredCloneinstead of JSON for complex deep cloning
Sign up for free to track which lessons you've completed and get learning reminders.