JSON & Data Serialization

10 questions found

How do you convert a JavaScript object into a JSON string?

Beginner
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

How do you convert a JSON string back into a JavaScript object?

Beginner
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

What values does JSON.stringify() silently drop or convert, and why does this matter?

Intermediate
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)

How do you use the replacer parameter of JSON.stringify() to control what gets serialized?

Intermediate
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

How does the reviver function in JSON.parse() work?

Intermediate
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)

Why does JSON.stringify() throw a TypeError on objects with circular references, and how do you handle it?

Advanced
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

How does defining a toJSON() method on a class customize its JSON.stringify() output?

Advanced
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

What is structuredClone() and how does it differ from JSON.parse(JSON.stringify(obj)) for deep cloning?

Advanced
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

How do you safely parse potentially untrusted JSON without exposing your app to prototype pollution?

Advanced
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

How would you stream-parse a very large JSON file without loading it entirely into memory?

Advanced
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