javascript – I want to create an object from deserialized properties

Question: Question:

I am writing a Web application that communicates with a server using JSON in Typescript. When serializing / deserializing to JSON, the method is not included in JSON, so I thought about creating an object using the deserialized data, but I don't know how to do it.

Right now I'm writing the following code.

class Pen{
    constructor(public color: String,public size:number) { }
    draw(): void {
        //do something
var json = JSON.stringify(new Pen("rgb(0,0,0)",10));
var pen_data = <Pen> JSON.parse(json);
//pen_data.draw(); //TypeError: pen_data.draw is not a function

var new_pen = new Pen(pen_data.color, pen_data.size);

However, this code needs to be rewritten one by one as the Pen properties increase, and if you want to do the same with other classes, you have to write similar code.

How can I write this code generically?

Answer: Answer:

I don't think there is a direct way. Whereas object-oriented "objects" deal with data and operations as a group, serialization saves or restores only the "data" part of an object, and in principle object-oriented "objects". This is because "objects" are incompatible with data persistence.

There are several possible solutions.

1. How to be patient and restore the properties according to the contents of each object

This is the sample code method presented by the questioner. Treat the Pen object and the corresponding JSON-formatted data completely differently. You have to call the constructor each time you deserialize, and modify the deserialization part each time the property increases or decreases. Anyway, it is troublesome and troublesome, and it is too redundant as the data structure is duplicated due to the existence of the Pen object and the corresponding JSON data, but it is a "right" method in a sense in object-oriented programming.

2. How to separate data and operations

Give up on the class and define draw as a separate function rather than a method of the Pen class. The Pen is not a class, but an interface, and the entity of the pen is just an object with no methods.

function draw(pen: Pen){

interface Pen { 
    color: String; 
    size: Number; 

var blackPen: Pen = { color: "rgb(0,0,0)", size: 10 };


var json = JSON.stringify(blackPen);
var pen = <Pen> JSON.parse(json);


I think it's a simple and straightforward method, and it has the advantage that even if the data structure becomes more complicated, it can be serialized / deserialized with a single stringify/parse . for example,

interface PaintTool {
    penList: [Pen];
    canvasWidth: Number;
    canvasHeight: Number;
    filePath: String;

Even for larger data structures that have Pen inside, such as, if the object does not have a method inside, the entire data structure can be serialized / deserialized in one shot. However, it has the disadvantage that you can hardly use the features that are typical of object-oriented programming such as classes and prototypes. Not available when Pen has subclasses and draw is overridden.

3. How to use the library for serialization

There is a way to use a library like resurrect-js . There are some restrictions, not every object can be serialized, and I haven't checked if it can be used for a TypeScript "class", but it's probably close to what the questioner envisions. I think it's the way.

According to the Readme, resurrect-js seems to be able to write:

function Foo() {}
Foo.prototype.greet = function() { return "hello"; };

// Behavior is preserved:
var necromancer = new Resurrect();
var json = necromancer.stringify(new Foo());
var foo = necromancer.resurrect(json);
foo.greet();  // => "hello"

I think it's intuitive to use, such as calling Resurrect#stringify method instead of JSON.strongify and Resurrect#resurrect instead of JSON.parse . The method also seems to be conditionally serializable. It depends on the application, but it seems worth considering.

4. How to forcibly restore by metaprogramming

JavaScript provides a very flexible metaprogramming method that allows you to mess with __proto__ directly, or Object.keys __proto__ find out the name of a property held by an object. You can check the constructor with the constructor property, or you can set some conventions to store the object's prototype in JSON data in the form of a string, and when deserializing, dynamically search for and call that constructor, and the prototype object. I don't think it's impossible to set and restore by setting properties (reference: dynamic object construction in javascript? ).

In Java etc., there is a function to perform such serialization by making full use of reflection. To make an object serializable in Java, you need to define a no-argument constructor because it is dynamically deserialized in that way. That's the way to do it with resurrect-js mentioned in 3. However, such a method may not always be usable for your own purposes. For example, the questioner uses TypeScript, so resurrect-js made for JavaScript may not always be diverted. If you can't use a library like resurrect-js, you can implement a similar mechanism on your own for your own purposes.

If we implement such a mechanism independently by making full use of metaprogramming, it would be possible to realize automatic serialization / deserialization according to the increase or decrease of properties, but that is the case. Metaprogramming is complicated, buggy, and not easy to handle. TypeScript static typing also doesn't help. It's never easy, so you should think of metaprogramming as a last resort.

I would choose 2. If you're not obsessed with object-oriented programming, I think it's the simplest and most straightforward method. I don't think it's inconvenient to use object-oriented classes and prototypes in this situation. I think this serialization problem is a good example of the shortcomings of object-oriented programming that puts data and operations together. The cause of the problem was trying to persist and restore persistent data such as color and size and non-persistent operation called draw method as an object called Pen without separating them. Yes, if you separate the data and the operation, the problem will be solved naturally.

Scroll to Top