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

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.