JS JSON & Data Serialization
Master modern JavaScript Object Notation (JSON): syntax invariants, deep serialization nuances, custom replacer & reviver transforms, circular reference traps, and the modern structuredClone() standard.
JSON Serialization & Rehydration Pipeline
JSON is a language-agnostic text serialization format. Traversing between live heap objects and transmission strings requires explicit awareness of data loss during type coercion.
1. JSON Syntax Rules & The Type Whitelist
JSON is strictly governed by ECMA-404. It is much stricter than JavaScript object literals: keys MUST be double-quoted, trailing commas are strictly forbidden, and only a whitelist of primitive and composite types is valid.
- String: Always in double quotes (e.g.
"title") - Number: Integers & floats (no
NaN, noInfinity) - Object: Key/value maps (
{ "a": 1 }) - Array: Ordered lists (
[1, "two", null]) - Boolean: Literal
trueorfalse - Null: Explicit
null
- Functions: Stripped completely from objects; converted to
nullin arrays - undefined: Stripped completely from objects
- Symbols: Ignored and omitted
- Date objects: Converted into ISO 8601 strings
- NaN & Infinity: Coerced to
null
2. Advanced Serialization: Replacers & Revivers
Both JSON.stringify() and JSON.parse() accept powerful transformer functions that let you redact sensitive passwords, format indentation, and restore native objects during parsing.
The Replacer & Reviver in Action
// 1. Redacting sensitive keys with a Replacer function
const user = { id: 101, name: 'Alice', passwordHash: 'secret_998', role: 'admin' };
const safeJson = JSON.stringify(user, (key, value) => {
if (key === 'passwordHash') return undefined; // Strips key!
return value;
}, 2); // 2 spaces indentation
// 2. Reviver function: Automatically rehydrating ISO strings into Date instances
const payload = '{"eventId": 42, "timestamp": "2026-09-29T16:00:00.000Z"}';
const parsed = JSON.parse(payload, (key, value) => {
// Check if string matches ISO date pattern
if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(value)) {
return new Date(value); // Restores real Date object!
}
return value;
});
console.log(parsed.timestamp instanceof Date); // ✅ true!
Test in Playground
3. Deep Cloning: JSON Hack vs Modern structuredClone()
Developers frequently used JSON.parse(JSON.stringify(obj)) as a crude deep clone hack. This hack breaks on Dates (becomes strings), RegExps (becomes empty objects), Maps/Sets (lost completely), and crashes on circular references.
The Native Standard: structuredClone()
const original = {
date: new Date(),
map: new Map([['key', 'val']]),
set: new Set([1, 2, 3]),
regex: /^[a-z]+$/gi
};
// Circular reference
original.self = original;
// ❌ FAILS with TypeError: Converting circular structure to JSON
// const badClone = JSON.parse(JSON.stringify(original));
// ✅ Modern Native Standard: Preserves Maps, Sets, Dates, Regex, and Cycles!
const deepCopy = structuredClone(original);
console.log(deepCopy.date instanceof Date); // true
console.log(deepCopy.self === deepCopy); // true (Cycle preserved!)
Run in Playground
Interactive Lab: JSON Validator & Beautifier
Live ValidatorPaste raw JSON below. Click "Beautify & Validate" to inspect parsing results, catch syntax errors with exact line numbers, or test indentation formatting.
// Validated output will appear here...
Build a Safe JSON Serializer that Handles Circular References
Build a safeStringify(obj, indent) function that serializes any JavaScript object without crashing on circular references. When a cycle is detected, replace the circular pointer with "[Circular]".
function safeStringify(obj, indent = 2) {
const seen = new WeakSet();
return JSON.stringify(obj, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return '[Circular]'; // Suppress cycle!
}
seen.add(value);
}
return value;
}, indent);
}
// Test:
const a = { name: 'Node A' };
a.self = a; // Circular pointer!
console.log(safeStringify(a));
// Output:
// {
// "name": "Node A",
// "self": "[Circular]"
// }
Chapter 32 Knowledge Check
Validate your understanding of JSON parsing, replacers, circular structures, and deep clone methods.
JSON.stringify() on an object with a circular reference?JSON.parse(str, reviver)?structuredClone() superior to JSON.parse(JSON.stringify()) for cloning objects?JSON.stringify() of an object?