JSON

Easy

JSON (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

Step 1: Create
let str = "hello";
Output
"hello"
1 / 4

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

Related Concepts