Custom object to JSON then back to a custom object?
Solution 1
One possible solution is the following:
function CardboardBox(n) {
if(typeof(n) == 'string') {
//build from name string
this.name = n;
} else {
//build from object
this.name = n.name;
}
//add in this object's "type" in a place
//that is unlikely to exist in other JSON strings
this.__type = 'CardboardBox';
}
var box = new CardboardBox("My Box");
send = JSON.stringify(box), // JSON CarboardBox()
obj = JSON.parse(send, function(key, val) {
//if this is an object, and is CardboardBox
if(typeof(val) === 'object' && val.__type === 'CardboardBox')
return new CardboardBox(val);
return val;
//or if your object is in a context (like window), and there are many of
//them that could be in there, you can do:
//
//if(typeof(val) === 'object' && context[val.__type])
// return new context[val.__type](val);
});
console.log(obj);
Basically store the object type in a place you know to look for later on when parsing the json. if you have multiple objects you can instantiate in a single scope the second parse method may be more appropriate. This also will account for objects in the JSON that are not CarboardBox
s.
Edit Here is a jsFiddle of this method in action.
Solution 2
Overall, you're correct: Javascript doesn't have any built-in way to serialize anything beyond plain objects, so going to and from JSON will not produce a particular class when you deserialize it. So you need to either work out serialization/deserialization yourself, or use a library that provides some support.
I personally like Backbone.js for this problem, as it handles serializing and deserializing quite well. You define a model class, which include a method to save its data to a server in a serialized form, and a method to deserialize it back to the model. The key design issue here is that deserializing is performed knowing the model you're deserializing to:
- you either call
myModel.fetch()
to get data from the server based on the model id, or - you pass a bunch of new data to the model constructor:
new Model(serializedData)
, or - you pass an array of data for multiple models to a collection that knows the model type:
new ModelCollection(arrayOfSerializedData)
.
What Backbone doesn't do is deal with type-casting data of an unknown type. When I've dealt with this, I've usually done something similar to @Chad's response, but using an intermediary; you could see this as a proxy model, or as a factory:
var classes = {
CardboardBox: ...,
AluminumBox: ...
}
function Deserializer(json) {
// parse if you're actually dealing with a string
var data = JSON.parse(json),
// now look for some custom type flag - you'll need to set this yourself
type = data.type,
// class lookup, perhaps with a default
Cls = classes[type] || DefaultType;
return new Cls(data);
}
var obj = new Deserializer(send);
obj instanceof CardboardBox; // should work
This still relies on a custom flag to switch types, though - I'm not sure there's any way around this.
Steve
Updated on July 01, 2022Comments
-
Steve almost 2 years
I've seen very similar questions to this, but I can't quite decide if they was answered clearly - maybe I'm being a bit dense, sorry.
I want to have the convenience (and clarity) of my own object, call it a
CardboardBox()
. It won't contain code, just data. I want to write this to a database and read it back later, but obviously, it is a typeObject()
when it's read back. All I can think of to find out what it used to be is:- Have a member variable
type
that I set to CARDBOARD_BOX - Instantiate a new
CarbardBox()
and use a function (in the box) to copy the properties ofObject()
to the newCardboardBox()
object
Is there a better way of doing this? I'm pretty sure I can change the actual type.
function CardboardBox() { this.type = "CARDBOARD_BOX" this.name = "No set"; this.populate = new function(obj) { // populate this object with obj properties } var box = new CarboardBox(); // CarboardBox box.name = "My Box"; send = JSON.stringyfy(box); . . . obj = JSON.parse(send); // Object if (obj.type == "CARDBOARD_BOX") { savedBox = new CardboardBox(); savedBox.populate(obj); }
Thanks in advance... Steve
[edit] My test code.
function CardboardBox(n) { this.name = n; } var box = new CardboardBox("My Box"); send = JSON.stringify(box); // JSON CarboardBox() obj = JSON.parse(send, function fn(obj) { // Object() returned log("OB: "+obj.type); return obj.type === 'CardboardBox' ? new CardboardBox(obj) : CardboardBox; }); console.log(obj);
Output is:
OB: undefined utils.js:40 OB: undefined utils.js:40 function CardboardBox(n) { this.name = n; }
- Have a member variable