My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Saturday, December 29, 2007

Is JSON forgetting something?

I played many times with JSON serialized data, creating odd alternatives too like JSTONE or JSOMON.

Few years ago I created even a PHP compatible serializzation but nowadays, with PHP5, json_encode and json_decode are natively integrated in PHP language and, at the same time, even faster than old serialize and unserialize global functions.



The big difference between JSON and PHP serializzation


Both JSON and PHP Serialized data have the same goal: transport objects and data over http protocol or storage these informations inside a cookie, a database or why not, a file.
However, PHP serialize and unserialize functions do more things than JSON serializzation, adding charset/indexes informations transporting even private or protected parameters.

With JavaScript 3rd edition We have not latter kind of properties so we shouldn't care about this limit during serializzation.

This is probably the most important difference between these two different serializzation but there is another one that should be easily implemented in JavaScript too: magic __sleep and __wakeup methods.



What do we need


The most important information we need to make JSON more magic than ever should be the constructor name. Without this information every kind of instance will lose its special methods/properties reducing them as a common Object.
Usually, this is exactely what we would like to transport, keys and values or, in the case of Array, only its values.
I'm thinking about something like that:


function A(){};
function B(){};
B.prototype.__wakeup = function(){
this.d = String.fromCharCode(this.c + this.a.charCodeAt(0));
};

var a = new A;
a.a = "b";
a.c = "d";
a.e = new B;
a.e.a = "b";
a.e.c = 3;
alert(encode(a));

// $("A",{"a":"b","c":"d","e":$("B",{"a":"b","c":3})})

I think that original objects doesn't need their constructor name.
In this way the unique change is for different instances and JSON syntax is quite the same.

With a string like that we should use eval too in a simple way:

function decode(str){
function $(constructor, o){
var result = eval("new ".concat(constructor)), key;
for(key in o){
if(o.hasOwnProperty(key))
result[key] = o[key];
};
if(typeof result.__wakeup === "function")
result.__wakeup();
return result;
};
return eval(str);
};

function A(){};
function B(){};
B.prototype.__wakeup = function(){
this.d = String.fromCharCode(this.c + this.a.charCodeAt(0));
};

var o = decode('$("A",{"a":"b","c":"d","e":$("B",{"a":"b","c":3})})');

alert([o instanceof A, o.e instanceof B, o.e.d]);


The __wakeup magic method should be used to do something before the object will be assigned, extremely useful in a lot of common situations.



What about __sleep?


The magic __sleep method should be the same used with PHP.
A simple prototype that could do everything but that needs to return properties we want to serialize.

This should be a JSON parser problem that could check every instance and use, only if it's present, its __sleep method.



Improvements



  • constructor name for instances that are not just objects

  • better server side parsers to manage instances without loosing their constructor name

  • a global name for dollar function, if some library use them as constructor too to avoid problems during instance creation (or a simple global-scope evaluation for each new "constructor" assignment)




This is just a personal brainstorming/proposal and I would like to know what do you think about that.

P.S. marry Christmas and happy new year :-)

1 comment:

Anonymous said...

but what if one of those your methods will have call to DB of file on HDD? If you transmit such seralized entity to different machine, you won't be able to deserialize it.

What you expect is not serialization in clear form, because you want to carry logic together with objects.