Sharing my Class class.

I’ve been using a little class utility to create classes for awhile and thought I’d share it and discuss what I did and why. First the goals, then code, then examples and discussion.

Goals

When I created this I basically wanted something that looked like a class instead of a function I was extending (I know, non-javascripty, but ecmascripty in laster versions), but that was still 100% native Javascript inheritance.

  • Looks like a class from other more OO languages
  • Uses native JS prototype inheritance so “myobj instanceof MyClass” still works.
  • Small, uncomplicated, don’t want tons of hacks and work-arounds.

Code

The most updated code can be found on github and requires the compat.js file in the same repository needs to be included for cross-browser compatibility if using in the browser: https://github.com/jacwright/jslib/blob/master/class.js

Examples and Discussion

To create a new class you new up an instance of Class like this:

var Person = new Class({
    constructor: function(name) {
        this.setName(name);
    },
    setName: function(value) {
        this.name = value || 'unknown';
    }
});
console.log(Person);

When you output the Person class you’ll see that it is actually just the constructor function. If you were to create this same Person class with regular Javascript you would get the exact same end result.

var Employee = new Class({
    extend: Person,
    constructor: function(name, title) {
        Person.call(this, name); // call the super-class constructor
        this.title = title;
    },
    setName: function(value) {
        if (!value) throw new Error('Employees must have a name.');
        Person.prototype.setName.call(this, value); // call super setName
    }
});
var jacob = new Employee('Jacob Wright', 'UI Guy');
console.log('Is employee?', jacob instanceof Employee);
console.log('Is person?', jacob instanceof Person);

Creating a sub-class is really easy. You use the word “extend” (not “extends” because that is a keyword in javscript/ecmascript) and assign it the class you’re extending. It uses javascript prototype extension under the hood. You end up with the exact same thing you would not using the Class class. You see I still call the super class constructor and methods the same as I would in normal Javascript. If you have the class in its own closure you could define a property “var parent = Person.prototype;” before the class and then change your calls to the super class to “parent.setName.call(this, value)” if you are so inclined.

You can also pass in “implement” and the methods on that class (or classes as you can also give it an array of classes) will get copied over to the prototype of this one. It is not actual inheritance so “instanceof” will not return true, and I don’t have any methods to ask if a class implements another, though that might be useful.

Statics are easy as well.

var Developer = new Class({
    extend: Employee
}, { // 2nd parameter is the static definition
    devs: {},
    factory: function(name) {
        if (this.devs.hasOwnProperty(name)) return this.devs[name];
        return this.devs[name] = new Developer(name, 'Developer');
    }
});
var jacob = Developer.factory('Jacob Wright');

Working Parts

Things I like about how it is implemented:
I thought it was stupidly clever to actually call the constructor “constructor” instead of “init” or “initialize” or whatever else other class helpers do. I don’t even have to remove it from the prototype since native prototypes define the constructor on them anyway. I only remove extend and implement from the prototype (though maybe I don’t even need to do that).

The empty constructor. You’ll see in the code there is an EmptyClass function. I use this in the prototype inheritance by assigning the prototype of the extended class to that of EmptyClass. Then I can create “new EmptyClass()” for the prototype chain and accomplish the same thing without running constructor code on the prototype object. This keeps the constructor of the parent class from getting called until you actually create a new instance of the class.
UPDATE: Using Object.create() does the same thing as using the empty constructor trick and I use that now to stick to standards.

Returning from a constructor. When a function returns a value and you attempt to create an object with the “new” operator, you actuall get back the returned value instead of a new class instance. If I were to return the number 42 from the Class function then “var num = new Class()” would give me 42 for num. You can see from the code that the Class constructor returns the impl.constructor. This is an interesting feature of Javascript and allows me to give back the constructor passed in the impl object (i.e. the prototype object) to the caller after I’ve set up its extend and implement parts.

Credits

Whether this is something useful or not I hope it is an interesting approach to the problem of OO and has helped you learn something new. I picked up the “empty constructor” trick from Prototype, the general idea of using “new Class” from MooTools, some of the implementation from ExtJS and the others, and then just simplified down as much as possible.

3 Responses to “Sharing my Class class.”

  1. Jeff Yamada Says:

    Thanks Jac!!!

  2. Michael J Says:

    Very nice Jac! This is quite elegant and just what I was looking for. Thanks for the effort.

  3. best wedding photographer Says:

    Awesome website…

    […]the time to read or visit the content or sites we have linked to below the[…]……