JSON.isRawJSON()
Tests whether a value is a marker object produced by JSON.rawJSON().
JSON.isRawJSON(value)- Added in JavaScript ES2025
Parameters
| Parameter | Type | Description |
|---|---|---|
$value | any | The value to test. Any value is accepted, including primitives, null, and undefined. |
Return value
booleantrue if the value was created by JSON.rawJSON(), false for every other value.
Changelog
- PHP ES2025Introduced alongside JSON.rawJSON() as part of the JSON source-text access proposal. Baseline newly available March 2025.
JSON.isRawJSON() answers one question: is this object the special marker that JSON.rawJSON() produces? It never throws and it never coerces — any value can be passed, and anything that is not a genuine raw JSON object returns false.
Reach for it when you are writing a serializer of your own. JSON.stringify() already understands these markers internally, so application code rarely needs the test. But a YAML emitter, a query-string builder, a logging formatter, or a schema validator that walks a data structure will otherwise see the marker as a plain object and emit {"rawJSON":"123"} or, because the object is frozen with a null prototype, something even less useful. Checking first lets you splice in value.rawJSON the same way the built-in does.
Why the identity check matters
The test looks for an internal slot, not for a property. An ordinary object literal that happens to have a rawJSON key returns false, and so does a copy made with spread or structuredClone(). That is deliberate: it means untrusted data cannot smuggle arbitrary text into a serializer's output by naming a field rawJSON.
Example
When to use it
- Add verbatim-number support to a custom YAML, CSV, or log formatter.
- Skip validation or transformation for values that are already finished JSON text.
- Assert in a test that a helper returned a real marker rather than a look-alike object.
Frequently asked questions
When would I ever call JSON.isRawJSON()?
Only when you write code that walks a data structure and produces text itself — a custom serializer, formatter, or validator. JSON.stringify() handles raw JSON markers without any help from you.
Why does my object with a rawJSON property return false?
The check tests for an internal marker installed by JSON.rawJSON(), not for a property name, so no hand-built object can pass it. This prevents parsed user input from injecting unescaped text into a serializer's output.
Does JSON.isRawJSON() throw on null or undefined?
No — it accepts any value and simply returns false for anything that is not a raw JSON object, so no typeof guard is needed before calling it.
More examples
Teaching a custom serializer about raw values
The raw check has to come before the typeof "object" branch, otherwise the marker is walked like a normal object. With it in place the id is written out with all twenty digits instead of being rounded or wrapped in braces.
function toYaml(value, indent = "") {
if (JSON.isRawJSON(value)) return value.rawJSON;
if (typeof value !== "object" || value === null) return JSON.stringify(value);
const inner = `${indent} `;
return Object.entries(value)
.map(([k, v]) => {
const text = toYaml(v, inner);
return text.includes("\n") ? `${k}:\n${inner}${text}` : `${k}: ${text}`;
})
.join(`\n${indent}`);
}
console.log(toYaml({ name: "Josh", userId: JSON.rawJSON("12345678901234567890") }));Look-alikes are rejected
The forged object matches the real one on every observable feature — frozen, null prototype, one rawJSON property — yet returns false, because the test reads an internal slot. Stringify agrees: the real marker emits 1.50, the forgery emits a nested object.
const raw = JSON.rawJSON("1.50");
const fake = Object.freeze(Object.assign(Object.create(null), { rawJSON: "1.50" }));
console.log(JSON.isRawJSON(raw), JSON.isRawJSON(fake));
console.log(JSON.stringify({ v: raw }));
console.log(JSON.stringify({ v: fake }));
console.log(Object.getPrototypeOf(raw), Object.keys(raw));Feature detection
On an engine without the feature the fallback emits the id as a quoted string, which at least preserves the digits. Both functions ship together, so testing one is enough in practice, but checking both is cheap.
const hasRawJSON =
typeof JSON.rawJSON === "function" && typeof JSON.isRawJSON === "function";
console.log("raw JSON support:", hasRawJSON);
const exactNumber = (digits) =>
hasRawJSON ? JSON.rawJSON(digits) : digits;
console.log(JSON.stringify({ id: exactNumber("12345678901234567890") }));
Discussion