thomasfrank.se

Classy JSON

June 9, 2006
Update August 31, 2006: A new/improved way of doing things
Classier JSON -- if you are new to the subject I suggest that you read this one instead.
The current trend among many JavaScript developers seems to be to write your code JSON style, i.e. to collect a number of functions/methods into a singleton object written in object notation.
If you need an introduction to this, I suggest reading JSON for the masses by Dustin Diaz.
I for one agree that this solves many problems:
  1. You don't clutter the global namespace.
  2. Your code gets more object-oriented and is easier to reuse.
  3. JSON notation tends to be easier to read than tradional constructors or plain old heaps of functions.

What about JSON and classes?

JSON objects are singleton objects by design, not by choice, since they have no constructor. I really like JSON, but I like classes too. Therefore I have written a small (5 kB) freeware library called classyJSON. Download it and use it to:
To use classyJSON you simply embed it in the head section of your web pages, before any other scripts that uses it.
<head>
<script type="text/javascript" src="classyJSON.js"></script>
...
</head>

Classify your objects

Let us start by writing our first class in JSON -- Vehicle. As you may notice, everything looks just like the creation of a normal JSON object up until .classify(), an object method which converts any object into a class:
// The Vehicle class
Vehicle={
	wheels:2,
	setWheels:function(x){
		this.wheels=x
	},
	getWheels:function(x){
		return this.wheels
	}
}.classify();

// Let's try to make some instances of Vehicle
myBike=new Vehicle();
myTractor=new Vehicle();
myTractor.setWheels(4);

// This should return "2 and 4"
alert(myBike.getWheels()+" and "+myTractor.getWheels());

Inheritance

To make a class inherit another class we use the constructor-method inherite():
// Be sure to include our previous definition of Vehicle here...
 
// The Car class (which inherits Vehicle)
Car={
	wheels:4
}.classify().inherit(Vehicle);

// This should return "4"
myCar=new Car();
alert(myCar.getWheels());

Multiple inheritance

You might have a class called Vehicle and another one called Investment and then decide that you want the Car class to inherit them both. You would write this as: Car={wheels:4}.classify().inherit(Vehicle, Investment).
Please note:

Private members

A while ago, Douglas Crockford pointed out that you can get private members in JavaScript objects -- properties (and methods) that only the methods of the object itself can reach.
I thought it would be nice if we could use those with our JSON style classes as well, so I wrote a few constructor-methods to make this possible:
Each of these methods takes one argument -- a comma-separated string that lists which members (or member data types) that should be made private or public.
An important thing to remember here is that each call to one of these functions resets the private/public state of the class members -- you can't combine the methods to set up a certain state. Let us look at an example:
// The Car class
Car={
	wheels:4,
	setWheels:function(x){
		this.wheels=x
	},
	getWheels:function(x){
		return this.wheels
	}
}.classify();

/* Some test instances
	(The "..Types"-methods will recognize the following data types: 
	object,array,function,string,number,boolean)   */
Car=Car.privateMembers("wheels,setWheels")
car1=new Car();
Car=Car.publicMembers("wheels");
car2=new Car();
Car=Car.privateMemberTypes("number"); 
car3=new Car();
Car=Car.publicMemberTypes("function")
car4=new Car();

// Let's check which public members each instance have
var x=""; var op=Object.prototype;
var inspect=function(x){var y=[]; for(var i in x){if(!op[i]){y.push(i)}};return y};
for(var i=1;i<=4;i++){x+="car"+1+"\t"+eval("inspect(car"+i+").join(', ')")+"\n"};
alert(x);

/* If everything works correct the alert should read like this:
	car1	getWheels
	car2	wheels
	car3	getWheels, setWheels
	car4	getWheels, setWheels	*/

Please note:

What about inheritance?

The good news is that the methods inherite(),deepCopy() and objJoin() will work with private members created with our private/public methods.

Copy objects

There is no built-in method in JavaScript that will copy objects -- assigning the value of an variable to an object variable will just create another pointer to that object. Sometimes pointers are what you want, sometimes you really want a new unique object -- so I added the object method deepCopy():
// The alert below will return "3 and 3" since "a" and "b" 
// are just different pointers to the same object
var a={wheels:4};
var b=a;
a.wheels=3;
alert(a.wheels+" and "+b.wheels);

// The alert below will return "4 and 3" since "a" and "b"  
// are pointers to two different unique objects
var a={wheels:4};
var b=a.deepCopy();
a.wheels=3;
alert(a.wheels+" and "+b.wheels);

Please note:

Join objects

To be able to join two or more objects into one often comes in handy. So, lo and behold, the object method objJoin():
// Three objects
var car={wheels:4};
var favlooks={color:"blue",look:"expensive"};
var priceRange={price:"cheap"};

// Let us join them in to one - myCar
myCar=car.objJoin(favlooks,priceRange);

// Now, let's check the members of myCar
var myCarMembers=function(){var x="";for(var i in myCar){
if(!Object.prototype[i]){x+=i+": "+myCar[i]+"\n"}};return x};
alert(myCarMembers());

// Of course objJoin() is an easy way to add members on the fly too
myCar=myCar.objJoin({maxSpeed:150,height:5,automatic:true});

// Let's check the members of myCar again
alert(myCarMembers());

Conclusion

That's about all. I hope classyJSON will provide you with a small framework that lets you use JSON for new classy things. Enjoy -- and feel free to bug report and comment below.
[comments]