Classify is a simple, reusable library for Javascript Class Inheritance without any dependencies. It also includes a Ruby-like system of Modules for namespacing and bundling methods. It's a good fit along side frameworks like jQuery for complex Javascript applications.
Classify's syntax is inspired by Foundation.js and uses concepts from John Resig's Simple Class Inheritance and Prototype.
Features
- Full Inheritance, with access to the super method
- Module Namespacing
- Add Module methods to Classes, Objects, and globally
Source
The project is hosted on Github. You can report bugs and propose features on the issues page.
Downloads
- Development Version (with comments)
- Production Version (minified)
Usage
Defining Methods
Defining methods is done using the def method.
Outside of a class or module definition, def
will define a method available globally.
def('hello', function() {
return 'Hello';
});
hello(); // 'Hello'
When given an object as the first argument, the method will be defined on that object.
var object = { name: 'John' };
def(object, 'hello', function() {
return 'Hello, ' + this.name;
});
object.hello(); // 'Hello, John'
If the method already exists on the object it will be overridden and reveal the previous method as this.callSuper
.
def(object, 'hello', function() {
return this.callSuper() + '!';
});
object.hello(); // 'Hello, John!'
Defining Classes
To make a class use the classify method, which is available globally:
classify('Dog', function() {});
var dog = new Dog();
This will create a Dog
class without any methods. To define new methods, use the def method:
classify('Dog', function() {
def('bark', function() {
return 'ruff';
});
def('fetch', function(object) {
return object;
});
});
var dog = new Dog();
dog.bark(); // 'ruff'
dog.fetch('stick'); // 'stick'
To define a constructor, define a method named 'initialize'
:
classify('Dog', function() {
def('initialize', function(name) {
this.name = name;
});
});
var dog = new Dog('Sparky');
alert(dog.name); // 'Sparky'
Inheritance
To inherit from another class, just pass the class to the classify method:
classify('Animal', function() {
def('speak', function() {
return 'Hello';
});
});
classify(Animal, 'Dog', function() {
def('speak', function() {
return this.callSuper() + ', ruff';
});
});
var animal = new Animal();
animal.speak(); // 'Hello'
var dog = new Dog();
dog.speak(); // 'Hello, ruff'
You have access to the super method by using this.callSuper
within the method definition. The super method will automatically get the arguments from the method definition, but you can also override them if need be:
classify('Vehicle', function() {
def('go', function(distance) {
return distance / this.speed;
});
});
classify(Vehicle, 'Car', function() {
def('go', function(distance) {
if (this.hasFuel) {
this.callSuper();
}
else {
this.callSuper(0);
}
});
});
var car = new Car();
car.speed = 100;
car.go(500); // 0
car.hasFuel = true;
car.go(500); // 5
Reopening
Classes can be reopened to add more methods or even to redefine methods:
classify('Dog', function() {
def('bark', function() {
return 'ruff';
});
});
classify(Dog, function() {
def('bark', function() {
return 'meow';
});
def('fetch', function(object) {
return object;
});
});
var dog = new Dog();
dog.bark(); // 'meow'
dog.fetch('stick'); // 'stick'
Native classes can also be reopened:
classify(String, function() {
def('dasherize', function() {
return this.replace(/_/g, '-');
});
});
.toString
When a class or module is defined, classify will create a .toString
method that return the name of the class, optionally including modules.
module('Animals', function() {
classify('Dog', function() {});
});
Animals.toString(); // 'Animals'
Animals.Dog.toString(); // 'Animals.Dog'
// and without modules
Animals.Dog.toString(false); // 'Dog'
Class instances will also return a useful string from #toString
:
new Animals.Dog().toString(); // '[object Animals.Dog]'
Defining Modules
You define modules by using the module function:
module('Animals', function() {});
You can use modules to namespace classes:
module('Animals', function() {
classify('Dog', function() {});
module('Felines', function() {
classify('Cat', function() {});
});
});
var dog = new Animals.Dog();
var cat = new Animals.Felines.Cat();
Methods defined on modules behave like class methods:
module('Inflector', function() {
def('dasherize', function(string) {
return string.replace(/_/g, '-');
});
});
Inflector.dasherize('underscored_name'); // 'underscored-name'
Note: This is different than the Ruby module implementation. This was done to simplify the code.
Include
Modules methods can be included into classes using the include method:
module('Inflector', function() {
def('dasherize', function() {
return this.replace(/_/g, '-');
});
});
classify(String, function() {
include(Inflector);
});
// or alternatively (if class is already defined):
// include(String, Inflector);
var string = 'underscored_name';
string.dasherize(); // 'underscored-name'
Extend
Module methods can be added as class methods using the extend method:
module('Inflector', function() {
def('dasherize', function(string) {
return string.replace(/_/g, '-');
});
});
classify(String, function() {
extend(Inflector);
});
// or alternatively (if class is already defined):
// extend(String, Inflector);
String.dasherize('underscored_name'); // 'underscored-name'
Class Methods can also be added using extend:
classify(String, function() {
extend(function() {
def('dasherize', function(string) {
return string.replace(/_/g, '-');
});
});
});
String.dasherize('underscored_name'); // 'underscored-name'
API
#def
def([object], name, definition)
Defines a new method. The method will be defined on the given object
or the current scope. Within the method definition, this
will refer to the current scope.
#classify
classify([superclass], object, definition)
Creates a new class. The class will be defined on the current scope. Optionally you can pass in a superclass as the first argument.
To define methods on the class, use the def
method.
classify('Dog', function() {
def('fetch', function(object) {
return object;
});
});
new Dog().fetch('stick'); // 'stick'
To define a constructor, define a method named 'initialize'
:
classify('Dog', function() {
def('initialize', function(name) {
this.name = name;
});
});
var dog = new Dog('Sparky');
alert(dog.name); // 'Sparky'
#module
module(object, definition)
Creates a new module. Modules can be used as namespaces for other modules and classes. They can also be used as a collection of method definitions to be included into other classes.
#include
include([object], definition)
Includes the given module methods into either the current class or, optionally, the given class definition. The included methods will be available on the instance of the class.
#extend
extend([object], definition)
Extends the current class or, optionally, the given class definition with the given module methods. The methods will be available as class methods.
If an object is given instead of a class, the methods will be added to that object.
var object = { name: 'John' };
extend(object, function() {
def('hello', function() {
return 'Hello, ' + this.name;
});
});
object.hello(); // 'Hello, John'
When used within a class definition, it will change the current scope so class methods can easily be added.
classify(Object, function() {
extend(function() {
def('isUndefined', function(object) {
return typeof object === 'undefined';
});
});
});
Object.isUndefined('hello'); // false
#alias
alias(alias, definition)
Creates a alias for the given method, class, or module definition.
classify(String, function() {
alias('upcase', 'toUpperCase');
});
'upcase'.upcase(); // 'UPCASE';
Changelog
0.10.8 Feb. 9, 2011
Cleaning up typeof
checks. Using strict equality only where appropriate.
0.10.7 Nov. 27, 2010
Refactoring the way methods are wrapped to access this.callSuper
.
0.10.6 Nov. 23, 2010
Refactoring to reduce file size when minified.
0.10.5 Nov. 17, 2010
Changing .toString
methods to optionally include module names. Added a #toString
method for class instances.
0.10.4 Nov. 15, 2010
Modules can now be created within class definitions
0.10.3 Nov. 11, 2010
Removing node support (because it was awkward - will revisit this in the future).
0.10.2 Oct. 29, 2010
Classes only inherit class methods not class properties.
0.10.1 Oct. 28, 2010
Setting the constructor property on the prototype of new classes, instead of the class itself.
0.10.0 Oct. 27, 2010
Any overridden method can now access the previous method using this.callSuper
. This functionality is no longer limited to class instance methods accessing the superclass' super method.
0.9.1 Oct. 22, 2010
extend
now takes objects to add methods to.
0.9.0 Oct. 22, 2010
Classes now inherit class methods/properties as well as instance methods/properties.
0.8.1 Oct. 14, 2010
Fixing namespace to work with Node a little more consistently.
0.8.0 Oct. 13, 2010
Changing the default namespace to this
to work in CommonJS.