Sunday, 4. October 2009, 10:15:06
The simplest thing is to create an empty class, that does not really include anything.
var A = $class();
var a = new A();
for (var x in a) {
alert(x + ", value: " + a[x]);
}
We create a class with $class, and we list its members. The only member is $parent, with the value undefined.
Now, let's add a simple class that has a constructor that sets x to 3.
var A = $class({
initialize: function() {
this.x = 3;
}
});
var a = new A();
alert(a.x);
Alerts 3 as expected.
We add a function, getX, to the class.
var A = $class({
initialize: function() {
this.x = 3;
},
getX: function() {
return this.x;
}
});
var a = new A();
alert(a.getX());
Still alerts 3.
We can let initialize take an argument, and send that argument to initialize through the new operation.
var A = $class({
initialize: function(x) {
this.x = x;
},
getX: function() {
return this.x;
}
});
var a = new A(3);
alert(a.getX());
This code also alerts 3.
We can add a function setX to the class that takes an argument.
var A = $class({
initialize: function(x) {
this.x = x;
},
getX: function() {
return this.x;
},
setX: function(x) {
this.x = x;
}
});
var a = new A(3);
a.setX(5);
alert(a.getX());
Alerts 5, variation!
It is time to inherit. A new class B, inherits A. It implements getY and setY.
var A = $class({
initialize: function(x) {
this.x = x;
},
getX: function() {
return this.x;
},
setX: function(x) {
this.x = x;
}
});
var B = $class(A, {
getY: function() {
return this.y;
},
setY: function(y) {
this.y = y;
}
});
var b = new B(3);
alert(b.getX());
Alerts 3. The argument we supplied to the B constructor was sent to the initialize function in A. This happened because class B didn't have an initialize function. You can also see that B has inherited the function getX.
So, what happens if we add an initialize function in class B?
var A = $class({
initialize: function(x) {
this.x = x;
},
getX: function() {
return this.x;
},
setX: function(x) {
this.x = x;
}
});
var B = $class(A, {
initialize: function(y) {
this.y = y;
},
getY: function() {
return this.y;
},
setY: function(y) {
this.y = y;
}
});
var b = new B(3);
alert(b.getX());
alert(b.getY());
First alerts undefined, then 3. So getX returns undefined, and getY returns 3. The initialize function in B was called, but not the one in class A.
We want to call the initialize function in class A, so we want to use $superinit.
var A = $class({
initialize: function(x) {
this.x = x;
},
getX: function() {
return this.x;
},
setX: function(x) {
this.x = x;
}
});
var B = $class(A, {
initialize: function(x, y) {
$superinit(this, x);
this.y = y;
},
getY: function() {
return this.y;
},
setY: function(y) {
this.y = y;
}
});
var b = new B(3, 4);
alert(b.getX());
alert(b.getY());
Alerts 3 and 4. Here we can see that the initialize function of class A was called with the help of $superinit. For $superinit to work, you need to supply this as the first argument, and the arguments that you want to send to the parent's initialize function as following arguments. Note that this is a little bit harder than in some other class implementations, but a verbosity that we can live with.
Time to try $super, which is basically the same as $superinit, but for all other functions.
var A = $class({
initialize: function(x) {
this.x = x;
},
getX: function() {
return this.x;
},
setX: function(x) {
this.x = x;
}
});
var B = $class(A, {
initialize: function(x, y) {
$superinit(this, x);
this.y = y;
},
getY: function() {
return this.y;
},
setY: function(y) {
this.y = y;
},
getX: function() {
return $super(this, "getX") + 2;
}
});
var b = new B(3, 4);
alert(b.getX());
Alerts 5. Class B implements getX by calling class A:s getX function with the help of the $super function, and adds 2 to that value. As in $superinit, the first argument is this. The second argument is "getX", you always need to declare the function that should be called in the super class. If the function that we call need its own arguments, we supply them after the first two arguments. This is also more verbose than in other class implementations, but I think it is good enough.
Time to introduce $extend. Extending a class that has already been created is a powerful concept, you can't do this in C++, but it is possible to do in Ruby. When you extend a class with a new function, you can use that function in already created functions of that class. (and of course, all of its sub classes)
function outputHello() {
if (a.printHello)
a.printHello();
else
alert("printHello function missing");
}
var A = $class();
var a = new A();
outputHello(a);
$extend(A, {
printHello: function() {
alert("Hello");
}
});
outputHello(a);
Alerts "printHello function missing", then alerts "Hello". First time, printHello does not exist on the a object, and the second time, after the $extend function call, we can call a.printHello(), since the A class now includes the printHello function.