Monday, December 31, 2007

[OT] Never forget old school!

Another year has gone, new technologies are coming but please never forget genuine old style. Happy new year to everyone from me and old "friend" :D

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 :-)

Friday, December 21, 2007

JavaScript Iterator for IE and other browsers

This is just my proposal to add Iterator in Internet Explorer and other browsers too.

(function(){

function Iterator(obj, name){
// Iterator(obj) and new Iterator(obj) behaviour
if(this instanceof Iterator){
var i = 0,
result = [],
skip = false,
key;
for(key in obj){
result[i++] = name ? key : [key, obj[key]];
this[key] = undefined;
if(!skip && (key == "constructor" || key == "toString" || key == "valueOf"))
skip = true;
};

// solve IE problems
for(var l = 0, arr = ["constructor", "toString", "valueOf"]; !skip && obj.hasOwnProperty && l < arr.length; l++){
if(obj.hasOwnProperty(arr[l])){
result[i++] = name ? arr[l] : [arr[l], obj[arr[l]]];
this[arr[l]] = undefined;
};
};

// add next method if any next in object
this.next = function(){
if(i === result.length)
throw new StopIteration;
else
return result[i++];
};

// reset result "pointer"
i = 0;
}
else
return new Iterator(obj, !!name);
};

function StopIteration(message, fileName, lineNumber){
this.message = message;
this.fileName = fileName;
this.lineNumber = lineNumber;
};
StopIteration.prototype = new Error;

// global scope check
if(!this.Iterator)
this.Iterator = Iterator;
if(!this.StopIteration)
this.StopIteration = StopIteration;
})();


// test it!
var iter = Iterator({a:"b", next:"c", toString:"hello"}),
output = [];
try{
while(true)
output.push(iter.next());
}
catch(err){
if(err instanceof StopIteration)
output.push("End of record");
else
output.push("Unknown error: " + err.description);
};
alert(output.join("\n"));


The best way to use them is with iter.next() method but you could use a for in loop too.
However, in latter case if the object has a next property, it will be overwrote by dynamic method but this problem apart, enjoy iterators :-)