JavaScript - JSON
Overview
Estimated time: 30–40 minutes
JSON is a text format for data interchange. Learn how to parse and stringify safely, customize serialization, handle dates, convert Map/Set, and avoid common pitfalls.
Learning Objectives
- Use
JSON.parse
andJSON.stringify
with replacer, reviver, and space parameters. - Serialize special types (Date, BigInt, Map/Set) using conventions.
- Detect/avoid circular references, and understand JSON limitations.
- Validate and safely consume JSON from untrusted sources.
Prerequisites
- JavaScript - Strings
- JavaScript - Template Literals (recommended)
- JavaScript - Map & Set (recommended)
Basics
// Stringify with pretty printing
const obj = { a: 1, b: [2, 3] };
JSON.stringify(obj); // "{"a":1,"b":[2,3]}"
JSON.stringify(obj, null, 2); // pretty (2 spaces)
// Parse
const s = '{"a":1,"b":[2,3]}';
const data = JSON.parse(s); // { a:1, b:[2,3] }
Replacer and reviver
// Replacer can filter or transform during stringify
const user = { id: 1, password: 'secret', name: 'Ada' };
JSON.stringify(user, (k, v) => k === 'password' ? undefined : v, 2);
// password omitted
// Reviver can post-process values on parse
const inJson = '{"created":"2025-09-05T12:00:00.000Z"}';
const revived = JSON.parse(inJson, (k, v) => {
if (typeof v === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(v)) return new Date(v);
return v;
});
revived.created instanceof Date; // true
Custom toJSON
// Objects can define toJSON to control serialization
class Point {
constructor(x, y) { this.x = x; this.y = y; }
toJSON() { return { x: this.x, y: this.y, type: 'Point' }; }
}
JSON.stringify(new Point(1,2)); // "{"x":1,"y":2,"type":"Point"}"
Dates, BigInt, Map/Set
// Dates serialize as ISO strings by default (via Date.prototype.toJSON)
const d = new Date('2025-09-05T12:00:00Z');
JSON.stringify({ d }); // {"d":"2025-09-05T12:00:00.000Z"}
// BigInt is NOT supported by JSON; convert explicitly
const bi = 12345678901234567890n;
JSON.stringify({ bi }); // TypeError
JSON.stringify({ bi: bi.toString() }); // OK: {"bi":"12345678901234567890"}
// Map/Set aren't supported; convert to arrays or objects
const m = new Map([["a",1],["b",2]]);
const s2 = new Set([1,2,3]);
JSON.stringify({ m: Object.fromEntries(m), s: [...s2] });
// {"m":{"a":1,"b":2},"s":[1,2,3]}
Circular references
// JSON.stringify throws on cycles
const a = { name: 'a' };
a.self = a;
// JSON.stringify(a) -> TypeError: Converting circular structure to JSON
// Safe stringify example: mark cycles as "[Circular]"
function safeStringify(value, space = 2) {
const seen = new WeakSet();
return JSON.stringify(value, (k, v) => {
if (typeof v === 'object' && v !== null) {
if (seen.has(v)) return '[Circular]';
seen.add(v);
}
return v;
}, space);
}
safeStringify(a); // works
Validation and safety
- Always use
JSON.parse
, nevereval
. - Wrap
JSON.parse
intry/catch
for untrusted input. - When embedding JSON in HTML, use
<script type="application/json">
and parse from.textContent
to avoid XSS.
Common Pitfalls
- Numbers: JSON has finite IEEE-754 numbers.
NaN
,Infinity
,-Infinity
serialize asnull
. - Unsupported types:
undefined
and functions are dropped in objects, becomenull
in arrays. - Property order: JSON does not guarantee key order; if you need stability, sort keys before stringifying.
- BigInt: Not supported—convert to string or number (risking precision loss).
Try it
Run to experiment with replacer, reviver, and special types: