Best way to serialize/unserialize objects in JavaScript?
JSON has no functions as data types. You can only serialize strings, numbers, objects, arrays, and booleans (and null
)
You could create your own toJson
method, only passing the data that really has to be serialized:
Person.prototype.toJson = function() { return JSON.stringify({age: this.age});};
Similar for deserializing:
Person.fromJson = function(json) { var data = JSON.parse(json); // Parsing the json string. return new Person(data.age);};
The usage would be:
var serialize = p1.toJson();var _p1 = Person.fromJson(serialize);alert("Is old: " + _p1.isOld());
To reduce the amount of work, you could consider to store all the data that needs to be serialized in a special "data" property for each Person
instance. For example:
function Person(age) { this.data = { age: age }; this.isOld = function (){ return this.data.age > 60 ? true : false; }}
then serializing and deserializing is merely calling JSON.stringify(this.data)
and setting the data of an instance would be instance.data = JSON.parse(json)
.
This would keep the toJson
and fromJson
methods simple but you'd have to adjust your other functions.
Side note:
You should add the isOld
method to the prototype of the function:
Person.prototype.isOld = function() {}
Otherwise, every instance has it's own instance of that function which also increases memory.
I wrote serialijse because I faced the same problem as you.
you can find it at https://github.com/erossignon/serialijse
It can be used in nodejs or in a browser and can serve to serialize and deserialize a complex set of objects from one context (nodejs) to the other (browser) or vice-versa.
var s = require("serialijse");var assert = require("assert");// testing serialization of a simple javascript object with datefunction testing_javascript_serialization_object_with_date() { var o = { date: new Date(), name: "foo" }; console.log(o.name, o.date.toISOString()); // JSON will fail as JSON doesn't preserve dates try { var jstr = JSON.stringify(o); var jo = JSON.parse(jstr); console.log(jo.name, jo.date.toISOString()); } catch (err) { console.log(" JSON has failed to preserve Date during stringify/parse "); console.log(" and has generated the following error message", err.message); } console.log(""); var str = s.serialize(o); var so = s.deserialize(str); console.log(" However Serialijse knows how to preserve date during serialization/deserialization :"); console.log(so.name, so.date.toISOString()); console.log("");}testing_javascript_serialization_object_with_date();// serializing a instance of a classfunction testing_javascript_serialization_instance_of_a_class() { function Person() { this.firstName = "Joe"; this.lastName = "Doe"; this.age = 42; } Person.prototype.fullName = function () { return this.firstName + " " + this.lastName; }; // testing serialization using JSON.stringify/JSON.parse var o = new Person(); console.log(o.fullName(), " age=", o.age); try { var jstr = JSON.stringify(o); var jo = JSON.parse(jstr); console.log(jo.fullName(), " age=", jo.age); } catch (err) { console.log(" JSON has failed to preserve the object class "); console.log(" and has generated the following error message", err.message); } console.log(""); // now testing serialization using serialijse serialize/deserialize s.declarePersistable(Person); var str = s.serialize(o); var so = s.deserialize(str); console.log(" However Serialijse knows how to preserve object classes serialization/deserialization :"); console.log(so.fullName(), " age=", so.age);}testing_javascript_serialization_instance_of_a_class();// serializing an object with cyclic dependenciesfunction testing_javascript_serialization_objects_with_cyclic_dependencies() { var Mary = { name: "Mary", friends: [] }; var Bob = { name: "Bob", friends: [] }; Mary.friends.push(Bob); Bob.friends.push(Mary); var group = [ Mary, Bob]; console.log(group); // testing serialization using JSON.stringify/JSON.parse try { var jstr = JSON.stringify(group); var jo = JSON.parse(jstr); console.log(jo); } catch (err) { console.log(" JSON has failed to manage object with cyclic deps"); console.log(" and has generated the following error message", err.message); } // now testing serialization using serialijse serialize/deserialize var str = s.serialize(group); var so = s.deserialize(str); console.log(" However Serialijse knows to manage object with cyclic deps !"); console.log(so); assert(so[0].friends[0] == so[1]); // Mary's friend is Bob}testing_javascript_serialization_objects_with_cyclic_dependencies();
I am the author of https://github.com/joonhocho/seri.
Seri is JSON + custom (nested) class support.
You simply need to provide toJSON
and fromJSON
to serialize and deserialize any class instances.
Here's an example with nested class objects:
import seri from 'seri';class Item { static fromJSON = (name) => new Item(name) constructor(name) { this.name = name; } toJSON() { return this.name; }}class Bag { static fromJSON = (itemsJson) => new Bag(seri.parse(itemsJson)) constructor(items) { this.items = items; } toJSON() { return seri.stringify(this.items); }}// register classesseri.addClass(Item);seri.addClass(Bag);const bag = new Bag([ new Item('apple'), new Item('orange'),]);const bagClone = seri.parse(seri.stringify(bag));// validatebagClone instanceof Bag;bagClone.items[0] instanceof Item;bagClone.items[0].name === 'apple';bagClone.items[1] instanceof Item;bagClone.items[1].name === 'orange';
Hope it helps address your problem.