Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to restore original object/type from JSON?

Its easy to load JSON into an object in javascript using eval or JSON.parse.

But if you have a proper "class" like function, how do you get the JSON data into it?

E.g.

function Person(name) {
  this.name=name;
  this.address = new Array();
  this.friendList;

  this.promote = function(){
     // do some complex stuff
  }
  this.addAddress = function(address) {
    this.address.push(address)
  }
}

var aPersonJSON = '{\"name\":\"Bob\",\"address\":[{\"street\":\"good st\",\"postcode\":\"ADSF\"}]}'

var aPerson = eval( "(" + aPersonJSON + ")" ); // or JSON.parse
//alert (aPerson.name);    // Bob
var someAddress = {street:"bad st",postcode:"HELL"};
//alert (someAddress.street); // bad st
aPerson.addAddress(someAddress); // fail!

The crux is I need to be able to create proper Person instances from JSON, but all I can get is a dumb object. Im wondering if its possible to do something with prototypes?

I dont want to have to parse each line of the JSON and assign each variable to the coresponding functions attributes, which would be too difficult. The actualy JSON and functions I have are much more complicated than the example above.

I am assuming one could JSONify the functions methods into the JSON string, but as I need to keep the resultant data as small as possible this is not an option - I only want to store and load the data, not the javascript code for the methods.

I also dont want to have to put the data loaded by JSON as a sub object if I can help it (but might be the only way), e.g.

function Person(name) {
  this.data = {};
  this.data.name=name;
}

var newPerson = new Person("");
newPerson.data = eval( "(" + aPersonJSON + ")" );
alert (newPerson.data.name); // Bob

Any ideas?

like image 833
John Little Avatar asked Dec 25 '12 02:12

John Little


1 Answers

You need to use a reviver function:

// Registry of types
var Types = {};

function MyClass(foo, bar) {
  this._foo = foo;
  this._bar = bar;
}
Types.MyClass = MyClass;

MyClass.prototype.getFoo = function() {
  return this._foo;
}

// Method which will provide a JSON.stringifiable object
MyClass.prototype.toJSON = function() {
  return {
    __type: 'MyClass',
    foo: this._foo,
    bar: this._bar
  };
};

// Method that can deserialize JSON into an instance
MyClass.revive = function(data) {
  // TODO: do basic validation
  return new MyClass(data.foo, data.bar);
};

var instance = new MyClass('blah', 'blah');

// JSON obtained by stringifying an instance
var json = JSON.stringify(instance); // "{"__type":"MyClass","foo":"blah","bar":"blah"}";

var obj = JSON.parse(json, function(key, value) {
  return key === '' && value.hasOwnProperty('__type')
    ? Types[value.__type].revive(value)
    : this[key];
});

obj.getFoo(); // blah

No other way really...

like image 140
Sean Kinsey Avatar answered Oct 03 '22 21:10

Sean Kinsey