View on GitHub

Moo.js minimalist object-oriented javascript framework (1.5kb)

A bit of javascript inheritance without forgetting everyone's names.


Js.create(ns, fn, config) creates a new class

  • ns [string]: namespace
    namespace in which the class will reside.
    it will automatically be created if it does not already exist.
  • fn [function]: constructor
    the function here must be declared with a name which will be the name of the class.
    ex: function MyClass(cfg){ ... }
  • config [object]: object containing all the class methods / attributes
    each of the properties will be public attributes / methods of the class instances.
    each class can include an (optional) init method which will be called when instanciated.

Because nothing speaks better than code:

// Define the class
Js.create('My.world', function Human(cfg){
    Js.apply(this, cfg); // apply config passed to object
    // apply some default values
    this.sex = cfg.sex || 'male'; // i'm a sexist god
},{
    sayHello: function(person){
        return this.name + " : Hello, " + person.name;
    },
    smile: function(){
        return this.name + " is smiling.";
    }
});

// Create some objects
var man = new My.world.Human({
    name: 'Adam'
});
var woman = new My.world.Human({
    name: 'Eve',
    age: 20,
    sex: 'female',
    xp: 50,
    sayHello: function(person){
        return "Hi!!";
    },
    sayBye: function(person){
        return "Bye " + person.name;
    }
});

// Play with some results
console.debug(man.name); // 'Adam';
console.debug(man.age); // undefined
console.debug(man.sex); // 'male'
console.debug(man.sayHello(woman)); // 'Adam : Hello, Eve'
console.debug(woman.name); // 'Eve'
console.debug(woman.age); // 20
console.debug(woman.xp); // 50
console.debug(woman.sex); // 'female'
console.debug(woman.sayHello(man)); // 'Hi!!'
console.debug(woman.sayBye(man)); // 'Bye Adam'
console.debug(typeof man); // 'object'
console.debug(man instanceof My.world.Human); // true

Inspecting the object in Chrome:

So far so good... Let's move on.

Js.create(ns, fn, config, superFn) extends a class

  • ns [string]: namespace
    namespace in which the class will reside.
    it will automatically be created if it does not already exist.
  • fn [function]: constructor
    the function here must be declared with a name which will be the name of the class.
    ex: function MyClass(cfg){ ... }
  • config [object]: object containing all the class methods / attributes
    each of the properties will be public attributes / methods of the class instances.
    each class can include an (optional) init method which will be called when instanciated.
  • superFn [function]: class to extend
    all the methods and properties are passed down to the new class.
    when overridden, they can still be accessible via the superclass property.

Because nothing speaks better than code:

// let's expand the Human class
Js.create('My.world', function Bum(cfg){
    // we can call the Human.init if we want
    this.superclass.call(this, cfg);
    this.name = "Bum " + this.name;
},{
    // override the regular way of saying hello
    sayHello: function(person){
        return this.name + " : Eh yooo " + person.name + ", spare 20 bucks?";
    },
    // additional methods
    sleep: function(){
        return "zzz...";
    }
}, My.world.Human);

// Populate the earth
var vagrant = new My.world.Bum({
    name: 'Nick',
    // override / extend at instanciation
    sayBye: function(person){
        return "Peace out.";
    }
});

// Play with some results
console.debug(vagrant instanceof My.world.Bum); // true
console.debug(vagrant instanceof My.world.Human); // true
console.debug(man instanceof My.world.Bum); // false
console.debug(vagrant.age); // undefined
console.debug(vagrant.name); // 'Bum Nick'
console.debug(vagrant.sex); // 'male'
console.debug(vagrant.sayHello(man)); // 'Bum Nick : Eh yooo Adam, spare 20 bucks?'
console.debug(vagrant.sleep()); // 'zzz...'
console.debug(vagrant.sayBye()); // 'Peace out.'

Inspecting the object in Chrome: This is where it gets really cool!!!

Because the class was created without using an anonymous function, each object retains their class name.
This is a huge help when debugging a complex hierarchical system

also included:

Js.Observable class that handles events

  • fire(ev, args...) triggers an event
    will trigger any callbacks for that event that have been registered for that event name.
    the callback functions are always passsing the scope and the args.
  • on(ev, function) creates a callback for an event
    registers a callback that will be called whever the event ev is fired.
    the events can also be registered during initialization through the events object.
  • un(ev) removes all the callbacks for that event
    clear the callback functions registered for the event ev.

Because nothing speaks better than code:

// let's create a new class that handles events
Js.create('My.world', function House(cfg) {
    this.superclass.call(this, cfg);
    this.life = 100;
}, {
    events: {
        burn: function(amount){
            console.debug('burning!!');
            this.life -= amount;
            if(this.life < 0){
                this.fire('die', this);
            }
        },
        die: function(){
            console.debug('the house is burned.');
        }
    },
    lightMatch: function(){
        this.fire('burn', 40);
    }
}, Js.Observable);

// Create a house object
var house = new My.world.House();
// we can also add custom events for that specific object
house.on('die', function(){ console.debug('it is ko.')});

// Play with some results
house.fire('burn', 35); // 'burning!!'
house.lightMatch(); // 'burning!!'
house.lightMatch(); // 'burning!!' 'the house is burned.' 'it is ko.'

Inspecting the object in Chrome:

Tested with Jasmine | Download: tar.gz | zip