There's no way to do it for JSON fetched from somewhere else.
If you have control over the JSON, then you can do this:
Add a "type" field to each object.
Tailor make a JSON function to handle this. This can be done in two ways, one secure, one insecure.
Secure method
Create a function stringifyJSONType()
. This one stringifies as usual, but adds a type parameter on-the-fly.
function stringifyJSONType(o){
o.type=o.constructor.name;
var s=JSON.stringify(o);
delete o.type; //To be clean and not modify the object.
return s;
}
Now, in the "secure" method, we have to create a switch-case for every type we expect for parsing. This only allows certain types (those which have been kept in the switch-case).
function parseJSONType(s){
var o=JSON.parse(s);
switch(o.type){
case "String":
o.__proto__=String;
break;
case "Date":
o.__proto__=Date;
break;
case "City": //Your custom object
o.__proto__=City;
break;
case "State": //Your custom object
o.__proto__=State;
break;
case "Country": //Your custom object
o.__proto__=Country;
break;
/*.... more stuff... */
case "Object":
default:
o.__proto__=Object;
break;
}
delete o.type;
return o;
}
Now, use these two methods just like JSON.parse()
and JSON.stringify()
, and it'll work. But for every new type you want to support, you'll have to add an extra case
.
Insecure method
Not too insecure, just that it uses the nefarious eval()
method. Which isn't too good.. As long as nobody else has the ability to add a custom type
parameter to your JSON, it's OK, though.
Here, you use the same stringifyJSONType()
as above, but use a different parse method.
function stringifyJSONType(o){
o.type=o.constructor.name;
var s=JSON.stringify(o);
delete o.type; //To be clean and not modify the object.
return s;
}
function parseJSONType(s){
var o=JSON.parse(s);
o.__proto__=eval(o.type);
delete o.type;
return o;
}
This has the advantage of not requiring switch-case and being easily extended to new types (no code changes required).