JSON & Data Serialization

10 questions found

JSON.stringify() serializes a JavaScript value into a JSON-formatted string, converting objects, arrays, strings, numbers, booleans, and null into their JSON text representation.
const obj = { name: 'Sam', age: 30 };
const json = JSON.stringify(obj);
console.log(json); // '{"name":"Sam","age":30}'
Real-world example Preparing a JavaScript object to send as the body of a fetch() POST request.

Common follow-ups: What happens to functions or undefined values when you stringify an object containing them?

Networking: Fetch XHR WebSockets & CORS
JSON.parse() parses a JSON-formatted string and returns the corresponding JavaScript value (object, array, string, number, etc.); it throws a SyntaxError if the string isn't valid JSON.
const json = '{"name":"Sam","age":30}';
const obj = JSON.parse(json);
console.log(obj.name); // 'Sam'
Real-world example Parsing a JSON response body received from an API into a usable JavaScript object.

Common follow-ups: How do you safely handle a JSON.parse() call that might fail on malformed input?

Error Handling
Functions, undefined, and Symbols are omitted entirely from objects (or converted to null inside arrays); Dates are converted to ISO strings; NaN and Infinity become null — meaning a round trip through JSON can silently lose or alter data types you didn't expect.
JSON.stringify({ fn: () => {}, val: undefined, date: new Date(), num: NaN });
// '{"date":"2026-08-08T00:00:00.000Z","num":null}'
// fn and val were dropped entirely
Real-world example A bug where a Date field silently becomes a plain string after being sent through an API, breaking date methods on the receiving end.

Common follow-ups: How would you restore a Date object after parsing JSON that stored it as a string?

Date Time & Internationalization (Intl API)
The second argument can be an array of allowed key names, or a function called for every key/value pair that returns the value to use (or undefined to omit that key) — giving fine-grained control over the output, like excluding sensitive fields.
const user = { name: 'Sam', password: 'secret123' };
JSON.stringify(user, (key, value) => key === 'password' ? undefined : value);
// '{"name":"Sam"}'
Real-world example Excluding a password or internal-only field before sending a user object to a client or logging it.

Common follow-ups: How does the 'space' third argument to JSON.stringify() affect the output?

Security: XSS CSRF & Content Security Policy
The optional second argument to JSON.parse() is called for every key/value pair as the object is being built, bottom-up, and its return value replaces the original — letting you transform values (like converting date strings back into Date objects) during parsing.
const json = '{"createdAt":"2026-08-08T00:00:00.000Z"}';
const obj = JSON.parse(json, (key, value) =>
  key === 'createdAt' ? new Date(value) : value
);
console.log(obj.createdAt instanceof Date); // true
Real-world example Automatically converting known date-string fields back into real Date objects right when parsing an API response.

Common follow-ups: Is the reviver called on the top-level object itself, or only on its properties?

Date Time & Internationalization (Intl API)
JSON has no concept of references, so stringify would need to serialize the same nested structure infinitely if an object refers back to itself (directly or indirectly) — the engine detects this and throws rather than looping forever. You can fix it by tracking visited objects yourself in a custom replacer, or using structuredClone for cloning instead.
const obj = {};
obj.self = obj; // circular reference
JSON.stringify(obj); // TypeError: Converting circular structure to JSON
Real-world example A bug where serializing a DOM node or a Vue/React internal object accidentally includes a circular parent reference.

Common follow-ups: How does structuredClone() differ from JSON.stringify/parse for cloning, especially with circular references?

Error Handling
If an object has a toJSON() method, JSON.stringify() calls it and serializes ITS return value instead of the object's own properties directly — a clean way to control exactly how a custom class is represented in JSON without a manual replacer.
class Money {
  constructor(cents) { this.cents = cents; }
  toJSON() { return (this.cents / 100).toFixed(2); }
}
JSON.stringify({ price: new Money(1999) }); // '{"price":"19.99"}'
Real-world example Making a Money or Temperature value object serialize as a simple display-friendly value instead of its internal representation.

Common follow-ups: Does Date's built-in toISOString-based JSON output work the same way, via its own toJSON() method?

Classes & Class Syntax
structuredClone() is a native deep-cloning function that correctly handles circular references, Maps, Sets, Dates, TypedArrays, and more — all of which the JSON round-trip technique either throws on or silently mangles. It's the modern, correct default choice for deep cloning.
const original = { date: new Date(), map: new Map([['a', 1]]) };
const clone = structuredClone(original);
console.log(clone.date instanceof Date); // true
console.log(clone.map instanceof Map);   // true
Real-world example Deep-cloning complex application state (including Dates and Maps) without the data-loss bugs of the JSON-based hack.

Common follow-ups: What kinds of values can structuredClone() NOT handle, like functions or DOM nodes?

Map Set WeakMap & WeakSet
Standard JSON.parse() itself is safe from prototype pollution since it produces plain data, but code that later merges parsed JSON into existing objects (e.g. a naive deep-merge) can be tricked into setting __proto__ or constructor.prototype if you don't explicitly guard against those keys.
function safeMerge(target, source) {
  for (const key of Object.keys(source)) {
    if (key === '__proto__' || key === 'constructor') continue; // guard
    target[key] = source[key];
  }
  return target;
}
Real-world example Safely merging untrusted JSON configuration from a user upload into an app's settings object.

Common follow-ups: Which popular libraries have had real prototype-pollution vulnerabilities from unsafe JSON merging?

Security: XSS CSRF & Content Security Policy
Standard JSON.parse() requires the full string in memory first. For huge files, use a streaming JSON parser (like a library built on Node's Readable streams or the browser's ReadableStream) that emits parsed tokens or objects incrementally as chunks of the file arrive.
// Conceptual: streaming parser emits events per JSON value
const parser = createStreamingJsonParser();
parser.on('value', (item) => processItem(item));
fs.createReadStream('huge.json').pipe(parser);
Real-world example Processing a multi-gigabyte JSON export file on a server without running out of memory.

Common follow-ups: What's a JSON Lines (.jsonl) format, and how does it make streaming parsing simpler?

Async Iterators & Streams