JavaScript JSON and Structured Data
Learn JSON syntax, parsing, serialization, revivers, replacers, formatting, failure handling, numeric limits, and durable data contracts in JavaScript.
Advanced
JSON is a language-independent data interchange syntax. ECMAScript defines how JSON text is parsed into ECMAScript values and how ECMAScript values are serialized back to JSON. Keep the boundary explicit: JSON is a data format, not JavaScript object-literal syntax.
This lesson builds from the JSON value model to parsing, serialization, revivers, replacers, formatting, failure handling, numeric limits, unsupported values, and durable data contracts. The goal is not merely to call JSON.parse and JSON.stringify, but to understand what crosses the serialization boundary and what does not.
The JSON value model
A JSON text represents one JSON value: an object, array, string, number, true, false, or null. JSON object member names are strings, and JSON has no JavaScript-specific values such as undefined, BigInt, functions, symbols, or class instances.
Runnable example
Output
Ready to run.
Quick check
Which value is valid JSON data?
JSON text is not a JavaScript object literal
JSON requires JSON syntax. Property names in JSON objects are strings, so {"name":"Ada"} is JSON text, while {name:"Ada"} is a JavaScript object literal but not valid JSON text.
Runnable example
Output
Ready to run.
Quick check
Why is {name:"Ada"} not valid JSON text?
JSON.parse turns text into data
JSON.parse accepts a string containing valid JSON text and returns the corresponding ECMAScript value. Parsing is a data boundary: the input is text until parsing succeeds.
Runnable example
Output
Ready to run.
Quick check
What does JSON.parse receive?
Invalid JSON fails with SyntaxError
Invalid JSON must not silently become a partial object. JSON.parse throws when the supplied text is not valid JSON. Treat parsing as an explicit failure point at input boundaries.
Runnable example
Output
Ready to run.
Quick check
How should code handle malformed JSON?
JSON.stringify serializes values
JSON.stringify converts supported ECMAScript values into JSON text. It returns a string for serializable values, while some top-level values such as undefined, functions, and symbols produce undefined.
Runnable example
Output
Ready to run.
Quick check
What does JSON.stringify return for a normal serializable object?
Unsupported values are not preserved as-is
JSON cannot represent every ECMAScript value. In objects, undefined, functions, and symbols are omitted; in arrays they become null. A top-level undefined, function, or symbol produces undefined.
Runnable example
Output
Ready to run.
Quick check
What happens to undefined inside an object?
Numbers have a JSON syntax and JavaScript limits
JSON has a decimal number grammar, but JSON itself does not define an arbitrary-precision integer type. When JSON numbers become ECMAScript Numbers, they use the Number representation. Values requiring exact integers beyond Number precision need an application-level strategy.
Runnable example
Output
Ready to run.
Quick check
What should you remember about very large integer values in JSON?
Formatting is part of serialization
The third JSON.stringify argument can add indentation for human-readable output. Formatting changes whitespace, not the underlying JSON data model.
Runnable example
Output
Ready to run.
Quick check
What does the third argument 2 do here?
Replacer functions control serialization
A replacer function can transform or exclude values while JSON.stringify walks the value. This is useful for deliberately shaping a wire representation, but it should be treated as part of the data contract.
Runnable example
Output
Ready to run.
Quick check
What does returning undefined from this object replacer do?
Revivers transform parsed data
JSON.parse accepts an optional reviver function. It walks the parsed structure and can transform values or return undefined to delete a property. This is useful for controlled interpretation of data after syntax has been validated.
Runnable example
Output
Ready to run.
Quick check
What can a reviver return to remove an object property?
toJSON can define an object representation
During JSON.stringify, an object can provide a toJSON method that returns the value to serialize. This is an explicit serialization hook and can intentionally expose a data representation different from the object’s internal shape.
Runnable example
Output
Ready to run.
Quick check
Why is the internal property absent from the result?
Duplicate JSON object names have defined parse behavior
JSON object member names are strings, and duplicate names can occur in JSON text. When JSON.parse processes duplicate names, later values overwrite earlier values for the same key.
Runnable example
Output
Ready to run.
Quick check
What value remains for role?
Round trips preserve data only within JSON’s value model
A parse/stringify round trip is not a universal clone operation. It preserves JSON-representable data, but unsupported values disappear or change representation, prototypes and methods are not preserved, and special application types need an explicit encoding.
Runnable example
Output
Ready to run.
Quick check
What is the safest description of JSON round trips?
Separate syntax validation from application validation
Valid JSON can still be the wrong shape for an application. Parsing answers “is this valid JSON and what ECMAScript value does it represent?” Application validation answers “does this value satisfy our required data contract?”
Runnable example
Output
Ready to run.
Quick check
Why is JSON.parse alone not enough for application input?
Keep serialization boundaries explicit
At a network, storage, or file boundary, make the conversion visible: text becomes data with JSON.parse, and data becomes text with JSON.stringify. Do not confuse a JavaScript object in memory with its serialized representation.
Runnable example
Output
Ready to run.
Quick check
Which sequence represents a normal JSON data boundary?
Recognize raw JSON objects with JSON.isRawJSON()
ECMAScript provides JSON.isRawJSON(obj) as a predicate for the special objects created for raw JSON serialization. It answers a narrow question: does this object carry the [[IsRawJSON]] internal slot? Ordinary objects, arrays, and primitive values are not raw JSON objects. This lesson uses the predicate to identify the value; the mechanics of constructing raw JSON text remain with JSON.rawJSON and the modern ECMAScript update pass.
Runnable example
Output
Ready to run.
Quick check
What does JSON.isRawJSON(obj) test?
Use the predicate with raw JSON values
When JSON.rawJSON is available, it creates the special raw-JSON object that JSON.isRawJSON can recognize. The predicate does not parse arbitrary text, validate an application schema, or determine whether a normal object would stringify successfully.
Runnable example
Output
Ready to run.
Quick check
If JSON.rawJSON("42") returns a value, what should JSON.isRawJSON(value) report?
Do not confuse raw-JSON identity with JSON validity
JSON.isRawJSON is not a general JSON validator. A normal object can be valid input to JSON.stringify without being a raw JSON object, while a raw JSON object is a special serialization value. Keep these questions separate: “Is this a raw JSON object?” and “Can this data be represented as JSON?”
Runnable example
Output
Ready to run.
Quick check
Which statement is correct?
Treat JSON.isRawJSON as a narrow protocol predicate
The predicate is useful when code needs to distinguish a raw-JSON serialization value from ordinary objects. It does not expose the internal slot itself, and it returns false for values that merely look similar. This keeps the special serialization protocol explicit instead of relying on shape-based checks.
Runnable example
Output
Ready to run.
Quick check
Why should code avoid checking only for a rawJSON property?
Design durable JSON contracts
A durable JSON contract uses explicit names, documented optionality, stable primitive representations, predictable arrays, and deliberate handling of dates, large integers, and versioning. JSON is the interchange syntax; your application still owns the meaning of the fields.
Runnable example
Output
Ready to run.
Quick check
What is a good authoring rule for JSON data contracts?
JSON.parse reviver context — inspect the matched source
The JSON.parse reviver can receive a context object for primitive values. Its source property exposes the matched JSON source text for that value, allowing a reviver to make decisions using the original representation rather than only the already-converted JavaScript value.
Output
Ready to run.
Quick check
What extra information can the modern JSON.parse reviver receive?
JSON.parse("{\"n\":1}", (key, value, context) => key === "n" ? context.source : value);
JSON.rawJSON() — controlled raw serialization
JSON.rawJSON() creates a special raw-JSON value for JSON.stringify. It lets an author preserve valid JSON text for a primitive serialization position without treating arbitrary application text as a JSON value. JSON.isRawJSON() remains the predicate for recognizing such a value.
Output
Ready to run.
Quick check
Why use JSON.rawJSON()?
const raw = JSON.rawJSON("42");
document.querySelector("#output").textContent = JSON.stringify({ value: raw });
Thanks for your feedback.
Mark this learning resource complete to track your learning progress.