While the Codio Client has a simple inheritance system in the form of the core/context
plugin, it leaves a little to be desired and is lacking in a few areas that I feel would greatly improve the readability of our code base, as well as providing a little extra functionality.
Javascript has no such thing as Classes, but it has several different ways to fake them. We need a clean and concise way to define and use classes, with the ability for constructors, inheritance and access to overridden methods.
John Resig posted an article a long time ago with his solution for Classes in Javascript. It's simple, but powerful, and is extremely readable, so it will form the basis of this proposal.
Every Class is defined using Class.extend
, which will give our new class the ability to have an init
constructor and inherit or be inherited.
var MyClass = Class.extend({
// The class constructor method, called when this class is initialized with `new MyClass();`.
init: function(){
// do something
},
// A public method.
myMethod: function(){
// do something else
}
});
Nice and simple!
Private methods are also non-existent in Javascript, but this Class system won't allow us to define private methods. We can of course simply define our private methods as functions outside of the class definition, but then these functions will not have access to our class, and its methods and variables.
We could expose our Class to a private function by either passing this
as a function argument, or by using call()
or apply()
. on the function. But this requires additional work, is messy and not very elegant. We also have testing to think about. Such private functions are completely untestable as they are not available outside of the module.
Private Class methods are therefore prefixed with an underscore to easily identify their visibility, and ensure maximum testability.
var MyClass = Class.extend({
// A public method.
myPublicMethod: function(){
// do something else
},
// A private method.
_myPrivateMethod: function(){
// do something else
}
});
If you are not sure if a method should be private or not, think about whether it will be called from outside it's class. If it won't be, then it is private.
Every attempt should be made to use 'real' private functions, which should be defined outside the class, but please be mindful of the this
context. Any function or method that requires this
to be the calling class, should be defined within the class and not as a 'real' private method. This is to ensure that this
is clearly identified.
Any Class can now easily and clearly inherit from any other class:
var Person = Class.extend({
init: function(isDancing){
this.dancing = isDancing;
},
dance: function(){
return this.dancing;
}
});
var Ninja = Person.extend({
init: function(){
this._super( false );
},
dance: function(){
// Call the inherited version of dance()
return this._super();
},
swingSword: function(){
return true;
}
});
var p = new Person(true);
p.dance(); // => true
var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true
// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class
I'm afraid I have one more point against this class based system. It adds new functions
.extend
to every object you create without any necessity of them being there. So I'm definitely in favor of using something likeutil.extend(child, parent);