thomasfrank.se

JSON stringify revisited

July 19, 2006

Update May 17, 2008: Small sanitizer added to the toObject-method.
Now toObject() will not eval() the string if it finds any malicious code in it.
For even more security: Don't set the includeFunctions flag to true.
To collect your client side JavaScript objects and store or manipulate them server side (or just have a good look at them while debugging) you need a JSON stringifier. It translates your object structure into a string that can be evaluated back to the original object. Recently I taught my old stringifier some new exciting tricks.
Douglas Crockford, father of the JSON concept, wrote one of the first stringifiers for JavaScript. Later Steve Yen at Trim Path wrote a nice improved version which I have used for some time.
It's my changes to Steve's version that I'd like to share with you. Basically they stemmed from my wish to make the stringifier:
Download the stringifier (3 kB) -- or just try out the interactive example on this page, which pretty much show how all of this can be done.

An example

In the example below we create a small array consisting of two objects, add a method to one of the objects, and add a new member to Object.prototype. We also set two circular references between the objects (parent and child).
This is an interactive example, by clicking the small Change this buttons you can remove the circular references and set different flags that affect JSONstring, our stringifier. You'll see the result immediately in the code comments.
// An array of people
var a=[
	{name:"Peter",age:40},
	{name:"Mary",age:20}
];

// Peter gets his own method
a[0].getOlder=function(){this.age++};

// And we extend the Object.prototype just for fun
Object.prototype.extra=1;

// Mary is Peter's child 
a[0].child=a[1];

// Which logically means Peter is Mary's parent
a[1].parent=a[0];


// Flags that affects the stringifier
// (default:false,false,false,true,true)
JSONstring.compactOutput=false;	
JSONstring.includeProtos=false;	
JSONstring.includeFunctions=false;	
JSONstring.detectCirculars=true;		
JSONstring.restoreCirculars=true;

// Now let us stringify this
var s=JSONstring.make(a);

/**/

// And check how converting the string back to an object works
var b=JSONstring.toObject(s);
var bTest=b[1]+", "+b[1].name;
if(b[1].parent){bTest+=", "+b[1].parent.name};

/**/

Conclusion

Traditional stringifiers choke on circular references, or get them wrong, creating two different objects out of one. This one doesn't.
If you want to use the restoreCirculars option to restore the circular structures you shouldn't change the structure of the JSON code with other parsers in between -- you can change values of non-objects though.
It is also nice to be able to include functions if you want to -- it doesn't really break the language independence of the JSON format either, but you might have to train JSON parsers written in other languages to ignore them.
And finally, for us slobs who occasionally extend the Object.prototype it is nice not to have to include those members in the data structure.
All in all this is a stringifier tuned a bit more for the complex data structures that are possible in JavaScript, rather than a "clean", but static, XML-like structure.

ActionScript

By the way, the stringifier part -- the make method, will work in ActionScript as well. (Just include the script in your movie with #include "jsonStringify.js"). But the toObject method with its restoration of circular structures won't. And ActionScript functions/methods can not be included in the data structure.
You will find other ActionScript stringifiers with "toObject" portions at json.org.
[comments]