Fork me on GitHub

Class Structure

In JS Burner Framework, writing application is more like Java. Framework does not use Javascript’s native class system. An important reason of using framework’s own class system is framework focuses on extended classes and super functions inside an instance.
JS Burner Framework uses AMD to write class modules.

Basis of Classes

Creating Classes

createClass main factory function to create classes. Methods are defined as properties of an object to pass it to createClass. To use properties, you access them with this.set(propertyName, value) and this.get(propertyName) methods. These methods are also placed automatically. After these examples, how to import createClass module will be explained.

var Animal = createClass({
    'init': function(name){
        //Constructor...
        this.set('name', name); //Not "this.name = name"
        console.log('New ' + name + ' born!');
    },

    'move': function(){
        var name = this.get('name');
        console.log(name + ' is moving...');
    },
    'sleep': function(){
        console.log(this.get('name') + ' is sleeping...');
    }
})

Creating Instances

After create a class, Class.new() function is placed automatically into class object to create instance of that class. If you notice that, new Class() is not the way to create instances for classes. You also pass arguments to init (constructor) function with this .new() function.

var animal = Animal.new('dog'); //Not "new Animal()"
/**
 * Console:
 * New dog born!
 */

animal.move();
/**
 * Console:
 * dog is moving...
 */

Extending Classes

After create a class, like .new() function, there is also .extend() function to extend the class. So you don’t need “createClass” module anymore to extend a class, if you have. If you overwrite a method, you can call parent’s method with this.super.method(). If you overwrite constructor method, you can call it just with this.super()

var Dog = Animal.extend({
    'init': function(){
        this.super('dog'); //Not "super()" w/o "this."
    },

    'bark': function(){
        console.log('Bark bark!');
    },
    'sleep': function(){
        this.super.sleep();
        console.log('It is dreaming...');
    }
});

var dog = Dog.new();
/**
 * Console:
 * New dog born!
 */

dog.bark(); //New method
/**
 * Console:
 * Bark bark!
 */
dog.move(); //Inherited method
/**
 * Console:
 * dog is moving...
 */
dog.sleep(); //Overwritten method
/**
 * Console:
 * dog is sleeping...
 * It is dreaming...
 */

var Golden = Dog.extend({
    'sleep': function(){
        this.super.super.sleep(); //This is also possible, it will bypass the middle class
    }
});

var golden = Golden.new();
/**
 * Console:
 * New dog born!
 */
golden.sleep();
/**
 * Console:
 * dog is sleeping...
 */

Interfaces & Implementation

Classes also can be implemented by interface(s). Interface structure is quite simple. It’s array of method names.

var interface = [
    'read',
    'write',
    'open',
    'close'
];

And to implement it just put a .implement() call to tail of class. .implement() method also returns class itself, so you don`t need to apply it at another line.

var Class = createClass({
    'read': function(){},
    'write': function(){},
    'open': function(){},
    'close': function(){}
}).implement(interface);

If one the methods defined in interface is missed, it will throw an error and warn the developer. Implementation also traces inherited methods, so if super class has a method which interface has, you don`t need to overwrite that method in new extended class.

Writing Class Modules

JS Burner framework uses Asynchronous Module Definition. And this is an example to write appropriate classes in Burner Framework.
createClass module is placed in core directory, and if you install framework under burner directory, you can define a class like this;

define(['burner/core/createClass'], function(createClass){
    return createClass({
        'init': function(){
            //Constructor...
        }
    })
})

Depths of Class System

Methods of Class Object

When you create or extend a class, these methods will be placed automatically;

Built-in Methods and Properties of An Instance

When you create an instance of a class, these methods will be placed automatically;

Method References in Instances

While writing classes, when you use this keyword, it will let you access just current and inherited super methods, not for methods defined in extended class later. Also if you overwrite a method in an extended class, and when you call an inherited method, and if that method calls another method which you has overwritten, it will call its own layer’s method, not overwritten method.
That’s why, if you write methods which returns instance itself, you have not to return this so that when you call an inherited method, that will return its layer and after that method, you can’t access extended methods.
It’s an example to show wrong usage;

var A = createClass({
    'aFunction': function(){
        return this;
    }
});

var B = A.extend({
    'anotherFunction': function(){
        return this;
    }
});

var b = B.new();
//Case 1, works
b.anotherFunction().aFunction();
//Case 2, does not work
b.aFunction().anotherFunction();

In case 1, anotherFunction returned this as B class, so next function reached aFunction because it is inherited to B.
In case2, aFunction returned this as A class, and anotherFunction is not defined or inherited in A, so it will throw an error.

To solve this cases, there is a special property of all instances: this.ref. This reference always gives last version of instance, so all methods can return instance successfully.

This is a correct example;

var A = createClass({
    'aFunction': function(){
        return this.ref;
    }
});

var B = A.extend({
    'anotherFunction': function(){
        return this.ref;
    }
});

var b = B.new();
//Case 1, works
b.anotherFunction().aFunction();
//Case 2, works
b.aFunction().anotherFunction();

Using this approach brings with it some responsibilities. You can use methods by putting them as tail to instance. However, in class methods you should not to use this approach. Because there may be an extended class(es) and they may overwrite some methods. In that case they may return incorrect instance layer to react a method.
It is an incorrect example;

var A = createClass({
    'funA': function(){
        console.log('A - funA');
        return this.ref;
    },
    'funB': function(){
        console.log('A - funB');
        return this.ref;
    },
    'doIt': function(){
        return this.funA().funB(); //Problematic    
    }
});

var B = A.extend({
    'funB': function(){
        console.log('B - funB');
        return this.ref;
    }
});

var b = B.new();
b.doIt();
/**
 * Console:
 * A - funA
 * B - funB
 */

As you see, when we call .doIt() after funA it called class B’s funB, not A’s. So while writing classes, you should not use tails approach.
Correct class A.doIt method definition;

function(){
    this.funA();
    this.funB();
    return this.ref;
}

or it is also can be used;

function(){
    this.funA();
    return this.funB();
}

Written with StackEdit.