JavaScript is a prototyped-based language, and yet it has the ability to mimic some of the features of class-based object-oriented languages. For example, JavaScript does not have a concept of public and private members, but through the magic of closures, it's still possible to provide the same functionality. Similarly, method overloading, interfaces, namespaces and abstract classes can all be added in one way or another.
Lately, as I've been programming in JavaScript, I've felt like I'm trying to turn it into a class-based language instead of using it in the way it's meant to be used. It seems like I'm trying to force the language to conform to what I'm used to.
The following is some JavaScript code I've written recently. It's purpose is to abstract away some of the effort involved in drawing to the HTML5 canvas element.
/*
Defines the Drawing namespace.
*/
var Drawing = {};
/*
Abstract base which represents an element to be drawn on the screen.
@param The graphical context in which this Node is drawn.
@param position The position of the center of this Node.
*/
Drawing.Node = function(context, position) {
return {
/*
The method which performs the actual drawing code for this Node. This method must be overridden in any subclasses of Node.
*/
draw: function() {
throw Exception.MethodNotOverridden;
},
/*
Returns the graphical context for this Node.
@return The graphical context for this Node.
*/
getContext: function() {
return context;
},
/*
Returns the position of this Node.
@return The position of this Node.
*/
getPosition: function() {
return position;
},
/*
Sets the position of this Node.
@param thePosition The position of this Node.
*/
setPosition: function(thePosition) {
position = thePosition;
}
};
}
/*
Define the shape namespace.
*/
var Shape = {};
/*
A circle shape implementation of Drawing.Node.
@param context The graphical context in which this Circle is drawn.
@param position The center of this Circle.
@param radius The radius of this circle.
@praram color The color of this circle.
*/
Shape.Circle = function(context, position, radius, color) {
//check the parameters
if (radius < 0)
throw Exception.InvalidArgument;
var node = Drawing.Node(context, position);
//overload the node drawing method
node.draw = function() {
var context = this.getContext();
var position = this.getPosition();
context.fillStyle = color;
context.beginPath();
context.arc(position.x, position.y, radius, 0, Math.PI*2, true);
context.closePath();
context.fill();
}
/*
Returns the radius of this Circle.
@return The radius of this Circle.
*/
node.getRadius = function() {
return radius;
};
/*
Sets the radius of this Circle.
@param theRadius The new radius of this circle.
*/
node.setRadius = function(theRadius) {
radius = theRadius;
};
/*
Returns the color of this Circle.
@return The color of this Circle.
*/
node.getColor = function() {
return color;
};
/*
Sets the color of this Circle.
@param theColor The new color of this Circle.
*/
node.setColor = function(theColor) {
color = theColor;
};
//return the node
return node;
};
The code works exactly like it should for a user of Shape.Circle, but it feels like it's held together with Duct Tape. Can somebody provide some insight on this?