JavaScript JSON Methods Table
| Piece | What it does | Field note |
|---|---|---|
JSON.stringify(obj) | Object to JSON string | Skips functions, undefined, and symbol keys silently |
JSON.stringify(obj, null, 2) | Pretty-print, 2-space indent | The null is the replacer slot; 4 also common |
JSON.parse(str) | String to object | Throws SyntaxError on invalid JSON - try/catch it |
JSON.parse(str, reviver) | Transform during parse | Reviver runs bottom-up on every value |
stringify(obj, replacer) | Filter keys on write | Array = allowlist; function = return undefined to drop |
toJSON() method | Custom serialization | If present, stringify uses its return value instead |
JSON.parse(JSON.stringify(o)) | The old deep copy | Loses Dates (to strings), Maps, Sets - use structuredClone |
JSON methods are the bridge between JavaScript objects and the text that travels over networks and into storage: JSON.stringify writes, JSON.parse reads. The table below is the working seven - the two core calls plus the options that filter, indent and transform - with the silent behaviors that bite only in production.
Bottom line: stringify silently DROPS values - undefined, functions and Symbols vanish (in objects they disappear, in arrays they become null), Dates serialize as ISO strings and come back as strings, and the round trip is lossy for anything beyond JSON's six types. The old JSON.parse(JSON.stringify(o)) deep-copy hack is retired: structuredClone() keeps Dates, Maps and Sets intact.
The honest part: parse is the one call that throws on user input, and it should - invalid JSON from a network or a user means the data contract failed. try/catch it at the boundary, log the string that failed, and the SyntaxError becomes diagnostics instead of a crash. The replacer and reviver hooks are the fix-it-in-place option: transform values during both directions without a second pass.
How to use
- Write with JSON.stringify(obj, null, 2) for human-readable output; drop the third argument for compact wire format.
- Read with JSON.parse inside try/catch for anything from users, networks or storage - the SyntaxError is the data contract failing loudly.
- Use the replacer (stringify) and reviver (parse) hooks to transform values in-flight - redact fields, revive date strings, filter arrays of keys.
Frequently asked questions
What values does JSON.stringify silently remove?
In objects: properties whose value is undefined, a function, or a Symbol disappear without error. In arrays the same values become null (positions preserved). Also transformed: Dates become ISO strings, NaN and Infinity become null (JSON has no concept of them), and Map/Set serialize as empty objects unless converted to arrays first. Knowing the drop list is knowing why an API response is suddenly missing a field - the value was there in memory, unrepresentable in JSON.
How does JSON.parse throw and how should I handle it?
It throws a SyntaxError with a position when the input breaks JSON grammar - trailing commas, single quotes, comments, actual newlines inside strings. Anything from a network, localStorage or a user belongs in try/catch; the error's message includes the character offset, which points at the exact broken byte. The production pattern: parse at the boundary, log the original string with the error, and return a typed failure to the caller instead of crashing.
What does the replacer argument in stringify actually do?
Two forms: an array of keys acts as an ALLOWLIST (everything else is dropped - the redaction tool), and a function runs on every key-value pair, returning the value to keep or undefined to drop it. The function form sees the key and value, which makes it the in-flight redactor: mask every field named email or ssn in one place instead of pre-copying the object. The reviver in parse is the mirror image, transforming values on the way in (the classic use: reviving ISO date strings into real Date objects).
Why is JSON.parse(JSON.stringify(o)) no longer the deep copy?
Because the round trip is lossy: Dates become strings, undefined values and functions vanish, Map and Set become empty objects, and Infinity becomes null - the copy passes the typeof tests and still quietly changed the data. structuredClone(o) (2022, all modern engines) deep-copies the full built-in set natively and faster. The string round trip survives only as a quick-and-dirty tool for JSON-safe data - and as the answer to 'why is my Date now a string' interviews.