thomasfrank.se
Classier JSON
August 31, 2006
A while ago I wrote an article called Classy JSON. The basic idea presented was that you should be able to create JavaScript classes from objects definied JSON style (as shown by Dustin Diaz in JSON for the masses).
In that article I also presented a script that creates classes from objects and handles inheritance. Some, like Ian Selby, liked my efforts, but there were also many who complained. Mostly about that I modified the Object.prototype.
To be fair I think you could make worse complaints about my old code if you study it in detail - it isn't very memory efficient and also does some rather hacky eval tricks to switch object members from private to public and back again. Nice functionality, but a murky implementation beneath the surface.
So no more of that - I'm back with a more basic, memory efficient and ten times as small script, with a nice prototypal inheritance pattern. And I steer clear of the Object.prototype.
The script
Here's my new script:
// jsonClass - a constructor of constructors
// is added as a method to the Array.prototype
Array.prototype.jsonClass=function(){
// Remember the array as x in closures/inner functions
var x=this;
// Create our object constructor
var constr=function(){
var a=arguments; var u;
for(var i=0;i<x.length;i++){
if(typeof x[i]=="object"){
for(var j in x[i]){this[j]=this[j]!=u?this[j]:x[i][j]}
};
if(typeof x[i]!="string" || a[i]===u){continue};
this[x[i]]=a[i];
}
};
// Prototype based inheritance of all superclasses
var nextProto=false;
for(var i=0;i<=x.length;i++){
var a=x[i]||constr;
if(typeof a=="function"){
a.prototype=nextProto||a.prototype;
nextProto=new a();
}
};
// Add a method to the constructor that lets us add
// members to a class (and subclasses) after it has
// been created
constr.addMembers=function(obj){
for(var i in obj){constr.prototype[i]=obj[i]}
};
// Return a our object constructor
return constr
};
You can also download it (0.5 kB without comments).
So how do we use that?
Well basically the script enables us to create classes/constructors from arrays. For such an array the following holds true:
- All objects get their members added to the class.
- All functions are treated as superclasses we want the class to inherit.
- All strings in the array are treated as names of object members we want to be able to initiate when we create a new object instance.
Class creation
Person=[
'name','height',
{
name:'John Doe (default name)',
height:'6 feet (default height)',
getName:function(){return this.name},
getHeight:function(){return this.height}
}
].jsonClass();
Inheritance
Here we create a class that inherits from another class:
Student=[
'name','height','grade',
Person,
{
grade:'C (default grade)',
getGrade:function(){return this.grade}
}
].jsonClass()
Instance creation
And here we create a new object - an instance of Student:
var Bob=new Student('Bob','5 ft 11 in','A');Adding members to a class
A nice thing about our prototypal inheritance is that we can add members to a class after it has been created.
// At the moment this would return undefined
alert(Bob.cool)
// Now we add cool to Bob's superclass
Person.addMembers({cool:'supercool'})
// And now this will return 'supercool'
alert(Bob.cool)
Conclusion
Thanks to Peter Foti for getting me to think a second time about classes and JSON.
I think this syntax is clean and efficient, but then again I like json-esque coding style a lot. Some don't. Let me know what you think!