JSON
EasyJSON (JavaScript Object Notation) is the universal data interchange format for the web. JSON.parse() converts JSON strings to JavaScript values, and JSON.stringify() does the reverse. Understanding the limitations, reviver/replacer functions, and edge cases (circular references, Date handling, undefined) is critical for working with APIs and data storage.
Interactive Visualization
String Immutability
let str = "hello";
Key Points
- JSON.parse(string) converts a JSON string into a JavaScript value
- JSON.stringify(value) converts a JavaScript value into a JSON string
- JSON cannot represent: functions, undefined, Symbol, circular references
- replacer parameter in stringify controls which properties are included
- reviver parameter in parse transforms values during parsing
- JSON.parse(JSON.stringify(obj)) is a quick deep clone (with limitations)
Code Examples
parse and stringify Basics
// JSON string → JavaScript object const jsonStr = '{"name":"Alice","age":30,"active":true}'; const user = JSON.parse(jsonStr); console.log(user.name); // "Alice" // JavaScript object → JSON string const data = { x: 1, y: [2, 3], nested: { z: 4 } }; const str = JSON.stringify(data); console.log(str); // '{"x":1,"y":[2,3],"nested":{"z":4}}' // Pretty-print with indentation console.log(JSON.stringify(data, null, 2));
parse converts JSON text to JS values. stringify converts JS values to JSON text.
What JSON Drops
const obj = { name: "Alice", greet: function() { return "hi"; }, age: undefined, id: Symbol("id"), count: NaN, big: Infinity, }; const result = JSON.parse(JSON.stringify(obj)); console.log(result); // { name: "Alice", count: null, big: null } // function → dropped, undefined → dropped // Symbol → dropped, NaN → null, Infinity → null
JSON silently drops functions, undefined, and Symbols. NaN and Infinity become null. Dates become strings.
replacer and reviver Functions
// replacer — control what gets stringified const user = { name: "Alice", password: "secret", role: "admin" }; const safe = JSON.stringify(user, (key, value) => { if (key === "password") return undefined; return value; }); console.log(safe); // '{"name":"Alice","role":"admin"}' // replacer as array — whitelist keys console.log(JSON.stringify(user, ["name", "role"])); // reviver — transform during parsing const json = '{"name":"Alice","joined":"2024-01-15T00:00:00.000Z"}'; const parsed = JSON.parse(json, (key, value) => { if (key === "joined") return new Date(value); return value; }); console.log(parsed.joined instanceof Date); // true
replacer filters/transforms during stringify. reviver transforms during parse. Both receive (key, value).
Deep Clone and toJSON
// Quick deep clone (with limitations) const original = { a: 1, b: { c: 2 }, d: [3, 4] }; const clone = JSON.parse(JSON.stringify(original)); clone.b.c = 99; console.log(original.b.c); // 2 (not affected!) // Circular references throw const obj = { name: "self" }; obj.self = obj; try { JSON.stringify(obj); } catch (e) { console.log(e.message); // "Converting circular structure to JSON" } // toJSON — custom serialization const account = { id: 1, balance: 1000, toJSON() { return { id: this.id }; }, }; console.log(JSON.stringify(account)); // '{"id":1}'
JSON clone works for plain data but fails on circular refs, Dates, functions. Use toJSON for custom output.
Common Mistakes
- Assuming JSON preserves Date objects (they become strings)
- Forgetting that JSON.stringify silently drops undefined and functions
- Using JSON clone on objects with circular references (throws error)
- Not validating JSON.parse input (wrap in try/catch for untrusted data)
Interview Tips
- List what JSON cannot represent: functions, undefined, Symbol, circular refs, Date objects
- Know the JSON deep clone trick and its limitations vs structuredClone
- Explain replacer and reviver with practical use cases
- Mention toJSON as a way for objects to control their own serialization