Suggest an editImprove this articleRefine the answer for “Json.parse and json.stringify in JavaScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**JSON.stringify()** converts a JavaScript value to a JSON string; **JSON.parse()** converts a JSON string back to a JavaScript value. ```javascript const obj = { name: 'Alice', age: 30 }; const str = JSON.stringify(obj); // '{"name":"Alice","age":30}' const back = JSON.parse(str); // { name: 'Alice', age: 30 } ``` **Key point:** stringify drops functions and Symbols silently; parse throws `SyntaxError` on malformed JSON.Shown above the full answer for quick recall.Answer (EN)Image**JSON.stringify()** converts a JavaScript value to a JSON string. **JSON.parse()** converts a JSON string back to a JavaScript value. ## Theory ### TL;DR - `stringify` packs an object into a portable text string; `parse` unpacks it back into a working object. - `stringify` drops functions, `undefined`, and Symbols silently; Dates become ISO strings; `BigInt` throws a `TypeError`. - `parse` validates strictly and throws `SyntaxError` on any malformed input. - Use both for: API request bodies, localStorage, config files on disk. - Skip both for: Dates you need as Date objects, functions, or circular references. ### Quick example ```javascript const user = { name: 'Alice', age: 30, active: true }; const json = JSON.stringify(user); // '{"name":"Alice","age":30,"active":true}' const parsed = JSON.parse(json); console.log(parsed.name); // 'Alice' console.log(typeof json); // 'string' console.log(typeof parsed); // 'object' ``` `stringify` gives you a plain string with no methods. `parse` gives back an object you can actually use. ### Key difference `JSON.stringify()` builds a string by recursively walking the value, calling `toJSON()` on objects that have it, and silently skipping anything without a JSON equivalent. `JSON.parse()` does the reverse but validates every byte against RFC 8259. Single quotes, unquoted keys, trailing commas - all of these throw. The round-trip is not lossless: what stringify drops cannot come back through parse. ### When to use - API requests: `JSON.stringify(body)` before sending, `response.json()` after receiving. - localStorage: `setItem('key', JSON.stringify(data))` to save, `JSON.parse(getItem('key'))` to load. - Debug output: `JSON.stringify(obj, null, 2)` for a readable, indented snapshot in logs. - Node.js config: `JSON.parse(fs.readFileSync('config.json', 'utf8'))` on app start. - Skip for: Dates, functions, classes, circular references, `BigInt`. ### What stringify changes or drops ```javascript const obj = { fn: () => 'hello', // dropped from object undef: undefined, // dropped from object sym: Symbol('id'), // dropped from object date: new Date('2023-01-01'), // becomes ISO string nan: NaN, // becomes null }; JSON.stringify(obj); // '{"date":"2023-01-01T00:00:00.000Z","nan":null}' // In arrays, undefined and functions become null: JSON.stringify([1, undefined, () => {}, 3]); // '[1,null,null,3]' // BigInt throws immediately - no silent conversion: JSON.stringify({ id: 123n }); // TypeError: Do not know how to serialize a BigInt ``` ### replacer and reviver Both methods have an optional parameter for custom handling. The `replacer` in `stringify` filters or transforms values on the way out. The `reviver` in `parse` restores types on the way in. ```javascript // replacer as array: property whitelist JSON.stringify({ name: 'Bob', password: 'secret' }, ['name']); // '{"name":"Bob"}' // replacer as function: handle BigInt JSON.stringify({ id: 123n }, (key, value) => typeof value === 'bigint' ? value.toString() : value ); // '{"id":"123"}' // reviver: restore Date objects after parse const json = '{"name":"Alice","birthday":"1990-06-15T00:00:00.000Z"}'; const result = JSON.parse(json, (key, value) => key === 'birthday' ? new Date(value) : value ); console.log(result.birthday instanceof Date); // true ``` The replacer is called top-down from the root; the reviver is called bottom-up, nested properties first. ### How V8 handles this internally In V8, `JSON.stringify()` runs through a C++ serializer that walks the object graph, writes primitives directly, and calls `toJSON()` when present. `JSON.parse()` is a recursive descent parser that validates UTF-8 and checks syntax per RFC 8259. Both run in native code. That is why they outperform any JavaScript-based JSON library by a wide margin. ### Common mistakes **1. Forgetting to parse after reading from localStorage** ```javascript localStorage.setItem('user', JSON.stringify({ name: 'Alice' })); // Wrong const raw = localStorage.getItem('user'); console.log(raw.name); // undefined - raw is a string, not an object // Fix const user = JSON.parse(localStorage.getItem('user')); console.log(user.name); // 'Alice' ``` In production apps this is probably the most common JSON bug. The storage layer always returns strings. **2. Expecting Date to survive the round-trip** ```javascript const obj = { birthday: new Date('1990-01-01') }; const clone = JSON.parse(JSON.stringify(obj)); console.log(clone.birthday instanceof Date); // false console.log(clone.birthday); // '1990-01-01T00:00:00.000Z' // clone.birthday.getFullYear() → TypeError // Fix: use a reviver const restored = JSON.parse(JSON.stringify(obj), (k, v) => k === 'birthday' ? new Date(v) : v ); console.log(restored.birthday instanceof Date); // true ``` **3. Circular references crash stringify** ```javascript const obj = { x: 1 }; obj.self = obj; JSON.stringify(obj); // TypeError: Converting circular structure to JSON // Fix: replacer with WeakSet function safeStringify(value) { const seen = new WeakSet(); return JSON.stringify(value, (key, val) => { if (typeof val === 'object' && val !== null) { if (seen.has(val)) return '[Circular]'; seen.add(val); } return val; }); } ``` **4. Passing a non-string to JSON.parse()** ```javascript JSON.parse({ a: 1 }); // SyntaxError // The object coerces to "[object Object]", which is not valid JSON. // Always pass an actual JSON string: JSON.parse('{"a":1}'); // { a: 1 } ``` **5. Using JSON for deep clone when you have special types** ```javascript const original = { date: new Date(), map: new Map([[1, 'one']]) }; const broken = JSON.parse(JSON.stringify(original)); // broken.date is a string, broken.map is {} // Use structuredClone() instead: const proper = structuredClone(original); console.log(proper.date instanceof Date); // true console.log(proper.map instanceof Map); // true ``` ### Real-world usage - React: persist state to localStorage via `stringify` on change, `parse` on mount (common in Next.js for theme preferences). - Express: `express.json()` middleware auto-parses incoming JSON bodies; `res.json()` auto-stringifies the response. - Node.js: `fs.writeFileSync('config.json', JSON.stringify(config, null, 2))` for human-readable config files. - Fetch API: `body: JSON.stringify(data)` on POST requests, `await response.json()` on the response. - Redux Persist: serializes store slices to localStorage between sessions. ### Follow-up questions **Q:** What happens to `undefined` in an object vs. in an array? **A:** In an object, the key is dropped entirely: `JSON.stringify({a: undefined})` gives `'{}'`. In an array, `undefined` becomes `null` to keep index positions: `JSON.stringify([undefined])` gives `'[null]'`. **Q:** `replacer` accepts both a function and an array. When do you choose the array? **A:** Use an array for a quick property whitelist: `JSON.stringify(user, ['name', 'email'])`. Use a function when you need conditional logic or type transformation across nested properties. **Q:** What is the difference between `JSON.parse()` and `eval()`? **A:** `eval()` executes arbitrary JavaScript, which is dangerous with untrusted data. `JSON.parse()` only accepts valid JSON and cannot run code. Always use `JSON.parse()` for data from external sources. **Q:** How does `JSON.parse()` handle duplicate keys in a JSON string? **A:** The last value wins. `JSON.parse('{"a":1,"a":2}')` returns `{a: 2}`. The spec permits duplicate keys, but producing them is always a bug in the source. **Q:** (Senior) Implement a stringify that handles circular references without any libraries. **A:** Track visited objects in a `WeakSet`. In the replacer function, check if the current value is already in the set before adding it. `WeakSet` is the right choice because it holds references weakly and does not block garbage collection. ## Examples ### localStorage: save and restore settings ```javascript const settings = { theme: 'dark', fontSize: 16, notifications: true }; // Save localStorage.setItem('settings', JSON.stringify(settings)); // Restore (guard against null - key might not exist yet) const raw = localStorage.getItem('settings'); const loaded = raw !== null ? JSON.parse(raw) : settings; console.log(loaded.theme); // 'dark' ``` Always check for `null` before calling `JSON.parse()`. `localStorage.getItem()` returns `null` for missing keys, and accessing properties on it later will throw. ### POST request with Fetch ```javascript async function createUser(data) { const response = await fetch('/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) // object → string for the wire }); if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); // parses the JSON response body } createUser({ name: 'Alice', role: 'developer' }) .then(user => console.log('Created with id:', user.id)); ``` `response.json()` is essentially `JSON.parse(await response.text())`. It throws if the response body is not valid JSON, so check `response.ok` first. ### replacer and reviver for edge cases ```javascript // Stringify: drop sensitive fields, handle BigInt const payload = { userId: 9007199254740993n, // too large for a safe JS number name: 'Bob', password: 'secret' }; const serialized = JSON.stringify(payload, (key, value) => { if (key === 'password') return undefined; // drop it if (typeof value === 'bigint') return value.toString(); // convert return value; }); // '{"userId":"9007199254740993","name":"Bob"}' // Parse: restore Date from API response const apiResponse = '{"id":1,"createdAt":"2023-06-15T10:00:00.000Z"}'; const record = JSON.parse(apiResponse, (key, value) => key === 'createdAt' ? new Date(value) : value ); console.log(record.createdAt instanceof Date); // true console.log(record.createdAt.getFullYear()); // 2023 ```For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.