JSON
02 / 06

JSON.parse & JSON.stringify

JSON.parse & JSON.stringify

The two core browser/Node.js APIs for converting between JSON strings and JavaScript values.

JSON.stringify — JS → string

JSON.stringify(value, replacer?, space?)

// Basic
JSON.stringify({ a: 1, b: 'two' })
// '{"a":1,"b":"two"}'

// Pretty-print (2-space indent)
JSON.stringify({ a: 1 }, null, 2)
// '{\n  "a": 1\n}'

// Replacer: filter keys
JSON.stringify({ a: 1, b: 2, c: 3 }, ['a', 'c'])
// '{"a":1,"c":3}'

// Replacer: transform values
JSON.stringify({ a: 1, b: 2 }, (key, val) =>
  typeof val === 'number' ? val * 2 : val
)
// '{"a":2,"b":4}'

What stringify drops

const obj = {
  a: 1,
  b: undefined,      // ← dropped
  c: () => {},       // ← dropped
  d: Symbol('x'),    // ← dropped
}
JSON.stringify(obj)  // '{"a":1}'

// In arrays, dropped values become null
JSON.stringify([1, undefined, () => {}, 3])
// '[1,null,null,3]'

JSON.parse — string → JS

JSON.parse(text, reviver?)

// Basic
JSON.parse('{"a":1}')   // { a: 1 }
JSON.parse('[1,2,3]')   // [1, 2, 3]
JSON.parse('"hello"')   // 'hello'
JSON.parse('true')      // true

// Reviver: transform values on the way in
JSON.parse('{"created":"2024-01-01"}', (key, val) =>
  key === 'created' ? new Date(val) : val
)
// { created: Date object }

Safe parsing pattern

function safeParse<T>(text: string): T | null {
  try {
    return JSON.parse(text) as T
  } catch {
    return null
  }
}

// JSON.parse throws SyntaxError on invalid input
JSON.parse('not json')  // SyntaxError: Unexpected token 'o'
JSON.parse(undefined)   // TypeError

toJSON() hook

// If an object has toJSON(), stringify uses its return value
class User {
  constructor(public name: string, private password: string) {}
  toJSON() {
    return { name: this.name }  // password is never serialised
  }
}
JSON.stringify(new User('Alice', 'secret'))
// '{"name":"Alice"}'

Deep clone caveat

// JSON round-trip is a quick deep clone — but lossy
const clone = JSON.parse(JSON.stringify(obj))

// Lost: undefined, functions, Symbol, Date (becomes string),
//       Map, Set, RegExp, class instances, circular refs
// For real deep clone: structuredClone() (modern) or lodash.cloneDeep

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free