JSON.parse(text, reviver) first parses the whole text into plain values, then walks the result bottom-up and calls reviver.call(holder, key, value, context) for every value:
- Order: post-order. An object's properties are revived before the object itself, and the root comes last with key
"". In{"a":{"b":1},"c":[2,3]}the keys arrive asb a 0 1 c "". thisis the object holding the value;keyis its property name (array indexes are strings).- Return value: whatever you return replaces the value. Returning
undefineddeletes the property (an array element becomes a hole).
Typical uses are turning date strings into Date objects, or dropping fields. A reviver cannot know the original type, so you decide by key or by shape.
The precision problem. By the time the reviver sees a number, the parser has already converted it to a double. 12345678901234567890 becomes 12345678901234567000 and 1.10 becomes 1.1.
Source text access (stage 4 in November 2025, listed for ES2026) fixes that with a third argument. For a primitive value (string, number, boolean, null) that is still unmodified, context.source is the exact text from the input, for example "12345678901234567890" or "1E2". For objects and arrays there is no source, and context is {}. It is also absent if an earlier reviver call replaced that value.
The matching write side is JSON.rawJSON(text). It returns a frozen, null-prototype object that JSON.stringify emits verbatim, so a BigInt can leave as a JSON number. JSON.isRawJSON(x) tests for it. rawJSON accepts only the text of a primitive: no objects or arrays, and no leading or trailing whitespace. Invalid text throws SyntaxError.
Availability: both ship in Node 22 and 24 (V8 11.4+, Chrome 114), Firefox 135, and Safari 18.4. Guard with typeof JSON.rawJSON === 'function' if you target older engines.