W3docs

JavaScript JSON

Learn to work with JSON in JavaScript: parse and stringify data, use revivers and replacers, pretty-print output, and deep-copy objects.

JavaScript Object Notation (JSON) is the backbone of data interchange on the web. Almost every API you call returns JSON, every config file you read is likely JSON, and every time the browser talks to a server, JSON is usually the format on the wire. This guide covers everything you need to work with JSON confidently in JavaScript: the syntax, the two core methods (JSON.parse and JSON.stringify), how to format and filter output, how to handle dates and deep copies, and the gotchas that trip people up in production.

What JSON is and why it matters

JSON is a lightweight, text-based data format that is easy for humans to read and write and easy for machines to parse and generate. It is language independent — even though its syntax is borrowed from JavaScript (Standard ECMA-262), virtually every language (Python, Java, C#, Go, Rust, PHP) can read and write it. That universality is exactly why it became the default format for REST APIs, config files (package.json, tsconfig.json), and localStorage.

The key thing to understand: JSON is a string, not an object. A JSON string only becomes a usable JavaScript object after you parse it, and a JavaScript object only becomes JSON after you stringify it. Most JSON work is moving between these two states.

Basic JSON syntax

JSON syntax is a strict subset of JavaScript object literal syntax:

  • Data is written as "key": value pairs
  • Pairs are separated by commas
  • Curly braces {} hold objects, square brackets [] hold arrays
  • Keys must be double-quoted strings (single quotes and unquoted keys are invalid)
  • Values may be a string, number, boolean, null, object, or array — but not undefined, a function, or a Date
{
  "name": "John",
  "age": 30,
  "isDeveloper": true,
  "languages": ["JavaScript", "Python", "Rust"]
}

Parsing JSON with JSON.parse()

JSON.parse() turns a JSON string into a JavaScript object (or array, number, etc.) that you can read and manipulate. In real code — especially when the JSON comes from a network request or user input — always wrap it in a try...catch, because malformed JSON throws a SyntaxError.

javascript— editable

Accessing nested data

Parsed JSON behaves like any other object, so you reach nested values with dot or bracket notation. This is the most common thing you do with an API response.

javascript— editable

Transforming values with a reviver

JSON.parse() accepts an optional reviver function as a second argument. It is called for every key/value pair, and whatever it returns becomes the final value — handy for converting types as you parse. A classic use is restoring Date objects (JSON has no date type, so dates arrive as strings).

javascript— editable

Stringifying objects with JSON.stringify()

JSON.stringify() does the reverse: it converts a JavaScript value into a JSON string, ready to send over the network or save to storage.

javascript— editable

Pretty-printing with indentation

The third argument controls spacing. Pass a number (spaces) or a string to produce readable, indented JSON — useful for logs, config files, and debugging.

javascript— editable

Filtering properties with a replacer

The second argument is a replacer. As an array of keys it whitelists which properties to keep — a quick way to strip out sensitive fields like passwords before sending data.

javascript— editable

As a function, the replacer is called for every key and lets you transform or drop values. Returning undefined from it omits that property.

javascript— editable

Custom serialization with toJSON

You can control how a specific object is serialized by giving it a toJSON() method. When JSON.stringify() encounters an object with this method, it calls toJSON() and serializes whatever it returns. (This is exactly how Date objects produce ISO strings — they have a built-in toJSON.)

javascript— editable

What stringify silently drops

JSON.stringify() is lossy by design. Knowing what it skips prevents confusing bugs:

  • undefined, functions, and Symbol values are omitted from objects (and become null inside arrays).
  • Date objects become ISO strings (via their toJSON).
  • NaN and Infinity become null.
  • BigInt throws a TypeError.
  • Circular references throw a TypeError.
javascript— editable

Advanced techniques and common patterns

Beyond the two core methods, day-to-day JSON work involves deep copying, handling dates, and processing arrays of records.

Deep copying objects

The JSON.parse(JSON.stringify(obj)) trick creates a deep copy — a clone whose nested objects are fully independent of the original, so mutating one never affects the other.

javascript— editable

It is quick and dependency-free, but inherits all of stringify's limitations: it drops functions, undefined, and Symbols, turns Dates into strings, and throws on circular references. For a faithful clone, prefer the built-in structuredClone(), which handles dates, maps, sets, and cycles.

javascript— editable

Working with dates

JSON has no date type, so dates travel as ISO 8601 strings. JSON.stringify writes them automatically, but on parse you get a plain string back — you must rebuild the Date yourself, either with new Date(...) or a reviver (shown earlier).

javascript— editable

Processing arrays of records

API responses are usually arrays of objects. After parsing, the standard array methods (forEach, map, filter) do the rest.

javascript— editable

JSON and the browser: fetch and localStorage

Two everyday places JSON shows up:

  • fetch: response.json() reads the body and parses it for you, so you rarely call JSON.parse on a fetch result directly — const data = await response.json();. See the Fetch API guide.
  • localStorage: it stores strings only, so stringify on the way in and parse on the way out: localStorage.setItem('user', JSON.stringify(user)) then JSON.parse(localStorage.getItem('user')).

Conclusion

JSON is the format you'll touch most often as a JavaScript developer, and it really comes down to two methods: JSON.parse() to turn a string into a value you can use, and JSON.stringify() to turn a value back into a string. Layer on the reviver and replacer arguments for type conversion and filtering, indentation for readable output, and toJSON for custom serialization, and you can handle almost any data-interchange task.

Keep the lossy edge cases in mind — dropped undefined/functions, stringified dates, and circular-reference errors — and reach for structuredClone() when you need a true copy rather than a JSON round-trip. With these tools you can confidently move data between your app, the server, and browser storage.

Practice

Practice
Which two methods convert to and from JSON in JavaScript?
Which two methods convert to and from JSON in JavaScript?
Practice
What happens to a property whose value is 'undefined' when you call JSON.stringify() on the object?
What happens to a property whose value is 'undefined' when you call JSON.stringify() on the object?
Practice
Why does JSON.parse(JSON.stringify(obj)) fail to fully clone an object containing a Date?
Why does JSON.parse(JSON.stringify(obj)) fail to fully clone an object containing a Date?
Was this page helpful?