fast-class

A faster and easier way to define Javascript Prototypal Inheritance: classes and mixins

Javascript-fastClass

A faster and easier way to define Javascript Prototypal Inheritance: classes and mixins

var Vehicle = Function.define(function(name)){//define the "base class" 
    this.name = name;//constructor initializer 
}, { //optionally specify  prototype members i.e. to be added on Vechicle.prototype 
    drawfunction() { console.log("Drawing a " + this.name + " vehicle."); }
});//optionally specify extra mixins i.e. , Wheels); 
 
var Car = Vechicle.inheritWith(function(basebaseCtor)){//define the "derrived class" 
    return { //optionally specify  prototype members 
        constructorfunction(namecolor) { //optionally specify a custom construcor 
            baseCtor.call(this, name);//ensure you are calling the baseCtor 
            this.color = color;
        },
        drawfunction() { //redefine the draw function on Car.prototype 
            console.log("Drawing a "+this.color+" car."); 
            base.draw.call(this);//optionally call the base class' draw method 
        }
    }
}, Engine);//optionally specify extra mixins whose prortotype members will be copied to Car.prototype 
 
//Define the Engine mixin 
function Engine() {
    //this constructor will be automatically called when creating any class using it  
    //(including derrived classes). i.e. new Car() in this example     
    this.powerSource = 'petrol';//these properties will be added to every Car instance 
    this.cmc = 1400;// i.e. var c= new Car(); c.cmc = 1400 
    this.horsePower = 140;
}.define({//optioanlly add custom methods on Engine.prototype mixin 
    //these will be copied to Car.prototype in our example, baecause it references the Engine mixin 
    isElectricfunction() { return this.pwerSource === 'electric'; }
})
 
var toyota = new Car("toyota prius", "red");//creating a new Car 
toyota.powerSouce; //petrol 
toyota.powerSource = 'electric'; //changing the powerSource property  
toyota.isElectric();//returns true 
toyota.draw(); 
//Drawing a red car.  
//Drawing a tyota prius vechicle. 

Native javascript inheritance is a pin in the ass. Even if you understand it perfectly it still requires some hideous repetivie code.

There are a lot of libraries which aim to help you with such that, but the main question is:

What is the fastest vs most convenient (also known as: with the most sugar) to create Prototypal Inheritance with?

You might want this library

  • when you can't use a language that compiles into javascript code.
  • because it is fast
  • you love writing less - doing more!

e.g. Google Closure, TypeScript, Coffee Script etc.

FastClass is a very tiny library (<1.5KB minified and gzipped) that helps you quickly derrive your classes so to speak. It comes in two flavours:

function(basebaseCtor) { this.somePrototypeMethod1 =  ...; this.somePrototypeMethod2 =  ...; } }

It makes usage of proto on all new browsers (which makes it blazing fast) except Internet Explorer <= 10 and maybe other ancient browsers where it fallbacks to for (var key in obj) statement.

Note __proto__ will become standard in ECMAScript 6

function(basebaseCtor) { return { somePrototypeMethod1: ..., somePrototypeMethod2: ...} }

whereas baseCtor is the function we want to inherit and base is it's prototype (baseCtor.prototype that is).

var Figure = function(name) {
    this.name = name;
    Function.initMixins(this);// since this is a top function, we need to call initMixins to make sure they will be initialized. 
}
Figure.prototype.draw = function() { console.log("figure " + name); }

You can define the first class' constructor function (same as above but with sugar syntax) as following:

var A = function(name) { 
    this.name = name; 
    Function.initMixins(this);// since this is a top function, we need to call initMixins to make sure they will be initialized. 
}.define({
    drawfunction() {
        console.log("figure "+ this.name);
    }
}/*, add any mixins here */) 

The define function copies all the members of the returned object to the function.prorortpe (A.prototype) and returns it (A)

This way we don't need to call Function.initMixins(this) as it will be automatically called for us

var A = Function.define(function(name){
    this.name = name;
}, {
    drawfunction() {//method added on function(name) {}.prototype 
        console.log("figure " + this.name);
    }
}

Alternatively you can pass an object with the costructor function specified (similar syntax to .inheritWith)

var A = Function.define({
    constructorfunction(name) {//the constructor itself can be even missing. If so we will add one for you! 
        this.name = name;
    },
    drawfunction() {//method added on constructor.prototype 
        console.log("figure " + this.name);
    }
}

All of the above methods are doing the same thing. You decide which one better suits you.

A classical example to use inheritance when you have a base class called Figure and a derrived class called Square.

To define the derrived class Square:

var Square = Figure.fastClass(function(basebaseCtor) {
    this.constructor = function(namelength) { 
      this.length = length;
      baseCtor.call(this, name);//calls the bacse ctor 
    }
    this.draw = function() {//redefines the draw function 
      console.log("square with length " + this.length);
      base.draw.call(this);//calls the base class' draw function 
    }
})

To define the derrived class Square:

var Square = Figure.inheritWith(function(basebaseCtor) {
    return { 
        constructor:  function(namelength) { 
            this.length = length;
            baseCtor.call(this, name);//calls the bacse ctor 
        },
        drawfunction() {//redefines the draw function 
            console.log("square with length " + this.length);
            base.draw.call(this);//calls the base class' draw function 
        }
    }
})

As you can see in both cases the definition is pretty simple and very similar.

However the .inheritWith flavour comes with about 5-15% performance boost depending on the actual browser and number of members. That is because we are simply setting __proto__ with the BaseClass.prototype for those browsers who support it (all nowdays browsers except IE<=10)

In both cases we the constructor is the function that is returned as the derrived class' constructor. The constructor is optional and we should only add it when we have some custom code as both functions will add it for us otherswise.

Whichever flavour you choose the code usage is the same. Firstly you need to instantiate the Constructor with the new operator:

var figure = new Figure("generic");
figure.draw();
//figure generic 
var square = new Square("10cm square", 10);
figure.draw(); 
//square with length 10 
//figure 10cm square 

Mixins are some grouped functionalities that you can add to a class without inheritance

You can learn more about mixins vs inheritance on this post.

We can define mixins as

  • an object containing functions
  • a function which will be executed for every instance of the class that is using it
    • The prototype of the function will be automatically copied to the class.prototype that are using it
// Animal base class 
function Animal() {
    // Private 
    function private1(){}
    function private2(){}
 
    // Privileged - on instance 
    this.privileged1 = function(){}
    this.privileged2 = function(){}
    Function.initMixins(this);
}.define({ 
    // Public - on prototype 
    method1function() { console.log("Animal::method1"); }
});

Alternatively the above can be defined as:

var Animal = Function.define(function(){
    // Private  
    function private1() {}
    function private2() {}
     // Privileged - on instance 
    this.privileged1 = function(){}
    this.privileged2 = function(){}
    }, {
        method1function() { console.log("Animal::method1"); }
    };
});

Or even simpler as an object providing the constructor:

var Animal = Function.define({
    constructorfunction(){ // the constructor is optional 
        // Private  
        function private1() {}
        function private2() {}
         // Privileged - on instance 
        this.privileged1 = function(){}
        this.privileged2 = function(){}
    },
    method1function() { console.log("Animal::method1"); }
});

The function Animal is the function given as first parameter. It acts as the constructor, which is invoked when an instance is created:

var animal = new Animal(); // Create a new Animal instance 

We can typically define a move action which is a set of methods grouped in our Move mixin

function Move() {//define the constructor of the mixin. This will be automatically called for every instance in the constructor of the class that is using this mixin 
    this.position = { x: 0, y: 0};
}.define({//define mixin's prototype. These will be copied to the prototype of the classes that will use this `mixin` 
   moveTofunction(xy) {
       this.position.x = x;
       this.position.y = y;
   },
   resetPositionfunction() {
       this.position.x = 0; 
       this.position.y = 0;
   },
   logPositionfunction() {
       console.log("Position: ", this.position);
   }
});

[[constructor]].inheritWith( function(base, baseCtor) { return {...} }, mixins ) - that function should return methods for the derrived prototype

// Extend the Animal class with inheritWith flavor 
var Dog = Animal.inheritWith(function(basebaseCtor) {
    //derrived class containing some private method(s) 
    function someOtherPrivateMethod() { }
    
    return {
        // Override base class `method1` 
        method1function(){
            someOtherPrivateMethod.call(this);
            base.method1.call(this);//calling a methd from the base class: Animal.prtotype.method1 
            console.log('Dog::method1');
        },
        scarefunction(){
            console.log('Dog::I scare you');
        },
        //some new public method(s) 
        method2function() { }
    }
}, Move);//specify any extra mixins to be added to the Dog's prototype 

Create an instance of Dog:

var husky = new Dog();
husky.method1(); 
// Animal::method1 
// Dog::method1 
 
husky.scare();
// Dog::I scare you' 
 
 
/// testing the mixin: 
husky.logPosition(); // Call the method of the mixin.  
// Position: {x: 0, y: 0} 
 
husky.moveTo(10, 20);  
husky.logPosition();
// Position: {x: 10, y: 20} 
 
husky.resetPosition();
husky.logPosition();
// Position: {x: 0, y: 0} 

[[constructor]].fastClass( function(base, baseCtor) { this.m = function {...} ... } ) - that function populates the derrived prototype Every class definition has access to the parent's prototype via the first argument passed into the function. The second argument is the base Class itself (its constructor i.e. Animal in our case):

// Same as above but Extend the Animal class using fastClass flavor 
var Dog = Animal.fastClass(function(basebaseCtor) {
    //private functions 
    function someOtherPrivateMethod() {};
    
    //since we don't set this.constructor, automatically will be added one for us which will call the baseCtor with all the provided arguments 
    //this is importat so we can set the new prototype into it 
    
    // Override base class `method1` 
    this.method1 = function(){
        someOtherPrivateMethod.call(this);
        // Call the parent function 
        base.method1.call(this);
        console.log('Dog::method1');
    };
    this.scare = function(){
        console.log('Dog::I scare you');
    };
    //some more public functions 
    this.method2 = function() {}; 
}, Move);

You can sometime extend a constructor or a function with some static methods In order to do so you need to call .defineStatic({...})

var F = function() {}.defineStatic({
    loadDatafunction() {...}
}).
typeof F.loadData // returns function 
F.loadData() //call the static function 

This can be easily mixed with Function.define

var F = Function.define({
    constructorfunction() {}
).defineStatic({//make sure you are adding it here and not on the constructor function itself.  
//that is because Function.define will automatically declare a function in order  
//to ensure Function.initMixins gets automatically called 
 
//add any static members here 
    loadDatafunction() {...}
};
typeof F.loadData // returns function 
F.loadData() //call the static function 

The Function.initMixins will always check for duplicate members that are already defined in the object i.e. the class defines a member whith the same name, or another mixin defines it. If such collision is found an exception will be thorwn when using the debug version of the library. Using the .min file there is no error and the member will be overriden.

However in order to prevent this exception you can define a function as abstract with .defineStatic(obj):

var Animal = Function.define({    
    method1function() { 
        throw new Exception("You need to implement method1 on your class's or mixin's prototype")
    }.defineStatic({abstract: true});//make this function abstract so it can be overriden by mixins 
});
var f = Function.abstract();
f();//will trigger a failed assert with message "Not implemented" 
var g = Function.abstract("Custom not implemented message");
g();//will trigger a failed assert with message "Custom not implemented message" 
f.abstract === true;//true 
var h = Function.abstract(function() { /* will be called before the assert "Not implemented" will be thrown */});
h();//will call the given function and then will trigger a failed assert with message "Not implemented" 
var j = Function.abstract("Custom not implemented message", function() { /* will be called before the assert "Not implemented" will be thrown */});
j();//will call the given function and then will trigger a failed assert with message "Custom not implemented message" 

Beside GitHub, you can download it as a Nuget package in Visual Studio fromhere

Install-Package Javascript-FastClass

Do you have a better & faster way? Share it! We would love to seeing creativity in action!