0

I know JSON.stringify doesn't stringify function, but what's the good practice because hydration is really exhausting. I don't want to create a new object. Any idea ?

class pers {
    name = "";
    last = "";

    constructor(name: string, last: string) {
        this.name = name;
        this.last = last;
    }

    alo() {
        alert(this.name);
    }
}

let pa = new pers("ben", "troq");
let s = JSON.stringify(pa);
let o = <pers>JSON.parse(s);
let pb = new pers("", "");

pb = o;
pb.alo();
John Weisz
  • 30,137
  • 13
  • 89
  • 132
Nod
  • 53
  • 2
  • 10
  • http://stackoverflow.com/questions/8111446/turning-json-strings-into-objects-with-methods – Luka Jacobowitz May 01 '16 at 15:53
  • 6
    Unrelated, but do yourself a favour and make the code consistent (put spaces around `=` everywhere, or do it nowhere if that makes you happier) and write out names (class `person`, with attributes `firstname` and `lastname` for example, instead of pers, name, last). What would `pa`, `s`, `o` and `pb` even stand for? – Sumurai8 May 01 '16 at 15:57

3 Answers3

4

The problem is this line:

let o = <pers>JSON.parse(s);

I belive you think this is a type-cast, but it is not. This is a type-assertion, which does not imply runtime support. Basically, you are only telling the compiler to believe o is of type pers, but that is not true at runtime:

o instanceof pers; // false

You will either need to manually create the object instance using your JSON as Nitzan suggests, or create a routine that reads some metadata information to automatically create the correct instances with the corresponding properties.


For the latter approach, I would recommend trying out TypedJSON, which I created to provide an elegant and widely adaptable solution to this exact problem:

@JsonObject
class pers {
    @JsonMember name = "";
    @JsonMember last = "";

    constructor(name?: string, last?: string) {
        this.name = name;
        this.last = last;
    }

    alo() {
        alert(this.name);
    }
}
let o = TypedJSON.parse(s, pers);
o instanceof pers; // true
o.alo(); // "ben"

Note the parameterless constructor, that is required (in most similar systems, as well).

This solution builds on ReflectDecorators, but it's not required (however, without it you will need to manually specify the constructor function of properties: @JsonMember({ type: String }) ... for example).

Community
  • 1
  • 1
John Weisz
  • 30,137
  • 13
  • 89
  • 132
1

How about separating the data from the functionality?

interface PersData {
    name: string;
    last: string;
}

class pers {
    private data: PersData;

    constructor(data: PersData | string) {
        this.data = typeof data === "string" ? JSON.parse(data) : data;
    }

    alo() {
        alert(this.data.name);
    }
}
Nitzan Tomer
  • 155,636
  • 47
  • 315
  • 299
1

replace:

let o  = <pers>JSON.parse(s);
let pb = new pers("", "");

pb = o;
pb.alo();

with:

let o  = JSON.parse(s);
let pb = Object.create(pers.prototype);
Object.assign(pb, o);

pb.alo();

It should work. Object.create (ES5.1) creates an object whose linked prototype is the one from the pers class but without running the pers constructor. Then Object.assign (ES6) copies the properties from the object unserialized from JSON to the object referenced by pb. Because the prototype was correctly set by Object.create calling the methods will work.

Nahuel Greco
  • 1,080
  • 14
  • 12
  • Can you explain your answer instead of just putting code in here? What is the key thing that makes your answer work? I ask because with an explanation others can learn from your answer and apply that to other questions. That is what stackoverflow is about --- not blindly copying & pasting some code. – Robert Dec 21 '16 at 17:48
  • Sorry, I thought the snippet was self-evident. Edited and added an explanation. – Nahuel Greco Dec 21 '16 at 20:56