tags:

views:

78

answers:

1

Hi,

Using jQuery, this is the format of most of the classes I write in JS:

$.Tabs = function(options){
var self = this;
this.defaults = {};
var cfg = $.extend(true, {}, this.defaults, options);
this.$elem = cfg.$elem;

function _init(){
    var dontInit = false;

    if (!cfg.$elem || !cfg.requiredProperty){
        alert('missing params');
        dontInit = true;
    }

    if (!dontInit){
        self.$elem.bridge(self);
    }
}

this.show = function(){};
this.hide = function(){};

_init();
}

The code above is just an example by the way.

My question is, how do you extrapolate common tasks/functionality from your classes, so every new class you write, you don't have to retype everything again?

I created a Class creation script based off of John Resig's Simple Javascript Inheritance pattern, which allows you to require certain parameters, bind event listeners for a pub/sub pattern, automatically combine defaults with options passed in, and it creates a bridge between the DOM element and the class instance (i.e $('elem').data('instanceNamespace', classInstance);)

But I'm uncomfortable with continuously using this class script to write my classes because it makes them less portable. But yet, I don't want all my classes to have so many similarities between them when it feels like those aspects can be abstracted.

Thoughts? Or how do you format your Javascript classes?

Thanks in advance.

Edit: Also, would anyone know the impact using a class creation script has on performance? I'm assuming the extra closures adds overhead but is it enough to make it not worthwhile to use?

+3  A: 

I think the idea you are looking for is called a Mix-in.

Note: what follows is just vanilla javascript, no jQuery, but I think you'll see that prototype inheritance is very well suited to the idea of mixins.

Let's say you define a simple constructor:

var Person = function(name){
    this.name=name;
    this.sayhello = function(){
        console.log(this.name + ' says hello');
    };
};

Then we can mixin new abilities by copying the properties over to the new object with the function below:

var extend = function(destination, source) {
    for (var property in source)
        destination[property] = source[property];
    return destination;
};

We can create some useful abilities that we may want to re-use for lots of different classes, so instead of having them all inherit from a common class, we can just mixin the new abilities at runtime:

var DanceMixin = {
    dance: function(){
        console.log(this.name + ' is dancing!');
    }
};

var SingMixin = {
    sing: function(){
        console.log(this.name + ' is singing!');
    }
};

var bob = new Person('bob'); 
extend(bob, SingMixin);
extend(bob, DanceMixin);

bob.sing();
/* bob is singing! */
bob.dance();
/* bob is dancing! */
bob.sayhello();
/* bob says hello */

Note that this is adding the new abilities to only a single object. If we wanted to add these abilities to all Person objects, we would need to modify the Person prototype.

Now let's say we have another trivial constructor for Animals:

var Animal = function(name){
    this.name = name;
    this.roar = function(){
        console.log(this.name + ' is roaring!');
    };
};

And let's say we want all of our animals to have the ability to dance. So we can add the DanceMixin to the Animal prototype using a function such as:

var mixin = function(dest, src){
    for (var property in src)
        dest.prototype[property] = src[property];
    return dest;
}
mixin(Animal, DanceMixin);

Now we can make some animals that can all dance...

var lion = new Animal('lion');
lion.dance()
/* lion is dancing! */

By the way, I highly recommend you check out the MooTools approach to the problem, which is quite elegant. Here is an example of using Implements in MooTools classes to facilitate mixins.

awesomo
Thanks for the reply. I should have mentioned that I do employ mixins, the class creation script (it's similar in format to mootools actually) I mentioned has the ability to extend classes with other classes or a json. I just felt like the class creation script was too abstracted, and all my classes would depend on it, I wouldn't be able to drop them into an existing project that doesn't already employ my script. I also meant more along the lines of private functionality for the class itself.
alex
@alex I think the trade-off of having your abstraction is probably worth the extra bytes of the dependency script. How large is your class creation script? I would think the size would pale in comparison to the size of an entire framework like jQuery that you are already including everywhere.
awesomo
@awesomo, true it's only 4kb
alex