JSON Reviver Function
Level: Intermediate
Just as you can control how JSON is created in JSON.stringify()
using toJSON()
methods in your objects, so too can you control how JSON strings are converted into objects in JSON.parse()
. This is done through a reviver function.
A reviver function is an optional second argument to JSON.parse()
that controls what objects are created as the JSON string (the first argument) is getting parsed. For each value in the JSON, starting from the bottom (most nested) up, the reviver is called and its return value determines what gets assigned in the generated object.
When called, the reviver receives two arguments, key
and value
. The key
will always be a string but the value
will be a pre-parsed value, either as the result of a previous reviver call or through standard JSON primitive parsing. Much like with toJSON()
, the top-level object will specify a key value of an empty string.
let json = '{ "prop": 1 }';
function reviverLogger (key, value) {
console.log(`reviver key: "${key}", value:`, value);
return value;
}
JSON.parse(json, reviverLogger);
/* logs:
reviver key: "prop", value: 1
reviver key: "", value: { prop: 1 }
*/
Used in combination with toJSON()
methods, the reviver can allow you to convert custom types to JSON and then from JSON back to the custom type. All you need is to know when a conversion is required. There’s no standard way of doing this, so the specifics of how this is done are ultimately up to you. For example, one approach might be to add a key to objects in the JSON structure that indicate the object’s type. The following example does this using a custom @type
key added in a toJSON()
and read back in a reviver function.
class Person {
constructor (name) {
this.name = name;
}
toJSON () {
return {
'@type': 'Person',
name: this.name
};
}
}
let people = [
new Person('Jay'),
new Person('Bob')
];
let json = JSON.stringify(people, null, 2);
console.log(json);
/* logs
[
{
"@type": "Person",
"name": "Jay"
},
{
"@type": "Person",
"name": "Bob"
}
]
*/
function peopleReviver (key, value) {
if (value?.['@type'] === 'Person') {
return new Person(value.name);
}
return value;
}
let parsedPeople = JSON.parse(json, peopleReviver);
console.log(parsedPeople);
// [ Person { name: 'Jay' }, Person { name: 'Bob' } ]
While this particular reviver only recognizes People objects, it could easily be expanded to handle more objects of different types.
More info:
More tips: JavaScript Tips of the Day