JavaScript OOP - the smart way

Prototype JavaScript library has had OOP for years, but their solution is very ugly. In this post I will describe a new elegant way of doing JavaScript OOP. My solution is heavily inspired by mootools.

AJS 3.5 is out and it includes this OOP scheme.

What we will implement:

JavaScript OOP d1

The Person class

We create a base class called Person:

Person = new AJS.Class({
    init: function(name) {
        this.name = name;
        Person.count++;
    },
    getName: function() {
        return this.name;
    }
});
Person.count = 0;

Notice that we have an init function, this is the class constructor and it will be called automatically when an instance is created. count is a static field.

UniversityPerson class

UniversityPerson extends the Person class:

UniversityPerson = Person.extend({
    init: function(name, school) {
        this.parent(name);
        this.school = school;
    },
    getSchool: function() {
        return this.school;
    }
});

Notice the this.parent call - it's used to call parent's constructor.

Student and Professor classes

Both classes extend UniversityPerson, and we write that following way:

Student = UniversityPerson.extend({
    init: function(name, school, id) {
        this.parent(name, school);
        this.student_id = id;
    },
    getStudentId: function() {
        return this.student_id;
    }
});

Professor = UniversityPerson.extend({
    init: function(name, school, cls) {
        this.parent(name, school);
        this.cls = cls;
    },
    getClass: function() {
        return this.cls;
    },
    getName: function() {
        return 'Professor ' + this.parent();
    }
});

We again use this.parent inside init function to call the parent's constructor. Notice that you also from getName can use this.parent, this will then call this.parent.getName - quite useful!

Creating instances

Creating some objects is really easy:

var amir = new Student('Amir', 'Aarhus University', 1);
var benny = new Student('Benny', 'Parrot University', 2);
alert(amir.getName()); //Amir
alert(benny.getStudentId()); //2

var johhny = new Professor('Johhny', 'JA University', 'Jack ass');
alert(johhny.getClass()); //Jack ass
alert(johhny.getName()); //Professor Johhny

GreyBox 5

I used this approach in GreyBox 5 and I am quite satisfied with the usage.

GreyBox 5 class diagram looks like this:

JavaScript OOP d2

Implementaion

The implementation is only around 35 lines of code:

AJS.Class = function(members) {
    var fn = function() {
        if(arguments[0] != 'no_init') {
            return this.init.apply(this, arguments);
        }
    }
    fn.prototype = members;
    AJS.update(fn, AJS.Class.prototype);
    return fn;
}

AJS.Class.prototype = {
    extend: function(members) {
        var parent = new this('no_init');
        for(k in members) {
            var prev = parent[k];
            var cur = members[k];
            if (prev && prev != cur && typeof cur == 'function') {
                cur = this._parentize(cur, prev);
            }
            parent[k] = cur;
        }
        return new AJS.Class(parent);
    },

    implement: function(members) {
        AJS.update(this.prototype, members);
    },

    _parentize: function(cur, prev) {
        return function(){
            this.parent = prev;
            return cur.apply(this, arguments);
        }
    }
}
25. Nov 2006 Announcements · Code · JavaScript
© Amir Salihefendic