If I have a class declaration in Javascript with a simple method as so:
class Foo {
constructor(a, b) {
this.a = a;
this.b = b;
}
sum() {
return this.a + this.b;
}
}
I can then create an object and call its sum()
method.
var bar = new Foo(2, 5); // {"a": 2, "b": 5}
var total = bar.sum(); // 7
I can also store this object (bar
) in a database or local storage by first converting it to a string:
localStorage.savedBar = JSON.stringify(bar); // "{\"a\": 2, \"b\": 5}"
However, when I retrieve it, I can no longer access its methods.
var retrievedBar = JSON.parse(localStorage.savedBar); // {"a": 2, "b": 5}
var secondTotal = retrievedBar.sum(); // retrievedBar.sum is not a function!
This is really annoying, as it means that I would have to reconstruct any class objects. I have to say,
var goodRetrievedBar = new Foo(retrievedBar.a, retrievedBar.b);
var goodSecondTotal = goodRetrievedBar.sum(); // 7
which might seem fine for this scenario, but as soon as I even think about more deeply nested data structures, I very quickly enter the land of for
loops and complex logic for a seemingly simple task. Also, if I wanted to make changes to my class in the future:
class Foo {
constructor(a, b, c) {
this.a = a;
this.b = b;
if (typeof c !== 'undefined') {
this.c = c;
}
}
sum() {
if (this.c) {
return this.a + this.b + this.c;
}
return this.a + this.b;
}
}
I would also have to update my parsing code to support the additional property, c
, when the changes I made to the class wouldn’t require me to make any other changes in my code.
Is there an easier way to force an object to assimilate itself into a class somehow? What is the standard way to deal with this in a simple and effective way?
>Solution :
Functions generally can’t be serialized and deserialized in all cases (due to closures), nor can objects with internal prototypes (other than Object.prototype
) have those prototypes reflected after deserialization.
What you can do is serialize the own-properties of the instance, then when deserializing, use Object.create
so that the internal prototype of the new instance is the class prototype.
class Foo {
constructor(a, b, c) {
this.a = a;
this.b = b;
if (typeof c !== 'undefined') {
this.c = c;
}
}
sum() {
if (this.c) {
return this.a + this.b + this.c;
}
return this.a + this.b;
}
}
const f = new Foo(1, 2, 3);
const stringified = JSON.stringify(f);
const retrievedInstance = Object.create(Foo.prototype);
Object.assign(retrievedInstance, JSON.parse(stringified));
console.log(retrievedInstance.sum());
Note that this approach won’t work if you have anything stored in closures somewhere in the original object rather than in properties on the instance.