If you create a custom implementation of the toJSON()
function for any class
objects, the standard JSON.stringify()
will work smoothly!
Map
s with Array
s as keys? Map
s with other nested Map
structures as values? A Map
nested inside a regular Object
? You can handle it all effortlessly by implementing your own toJSON()
.
Map.prototype.toJSON = function() {
return Array.from(this.entries());
};
That's all there is to it!
You need to manipulate prototypes in this case. While you could manually add toJSON()
to every non-standard object or structure, leveraging JavaScript's capabilities is much more powerful.
DEMO
test = {
regular: 'object',
map: new Map([
[['array', 'key'], 7],
['stringKey', new Map([
['innerMap', 'supported'],
['anotherValue', 8]
])]
])
};
console.log(JSON.stringify(test));
This code snippet outputs:
{"regular":"object","map":[[["array","key"],7],["stringKey",[["innerMap","supported"],["anotherValue",8]]]]}
However, deserializing back to true Map
structures isn't as straightforward. To demonstrate, I'll reconstruct the maps from the resulting string to retrieve a value:
test2 = JSON.parse(JSON.stringify(test));
console.log((new Map((new Map(test2.map)).get('stringKey'))).get('innerMap'));
The output is
"supported"
While this process may seem cumbersome, with some added special handling, you can automate deserialization as well.
Map.prototype.toJSON = function() {
return ['window.Map', Array.from(this.entries())];
};
Map.fromJSON = function(key, value) {
return (value instanceof Array && value[0] == 'window.Map') ?
new Map(value[1]) :
value
;
};
Now the serialized JSON looks like this:
{"regular":"object","test":["window.Map",[[["array","key"],7],["stringKey",["window.Map",[["innerMap","supported"],["anotherValue",8]]]]]]}
And deserializing and using it becomes simple with Map.fromJSON
:
test2 = JSON.parse(JSON.stringify(test), Map.fromJSON);
console.log(test2.map.get('stringKey').get('innerMap'));
The output remains the same without creating new instances of Map()
DEMO