Fun With MooTool Part 3: Class Mutators
he Class system in [Mootools](http://mootools.net) a exceptionally powerful for the little amount of code that it is comprised of. A large part of that power comes from the Mutator system. A Mutator can be thought of a lot like a plug-in. However unlike most plug-ins that are executed at run time, Mootools Mutators are executed at the time a class is [actually defined](http://github.com/mootools/mootools-core/blob/master/Source/Class/Class.js#L76) altering the end result of the class
A Mutator is nothing more than a JavaScript function that has access to the internals of the class it is attached to. These functions are stored in a Mutators namespace in the Mootools library. Each mutator manifests itself as a special key on your class and the value of the key is the argument that will be passed to the associated function. out of the box, Mootools ships with two simple mutators, Extends and Implements.
Extends does basically what it sounds like - Extends one JavaScript Class / Object, making the JavaScript inheritance model look more classical. Under the hood, it is still doing prototypical inheritancee, so you can extend any vanilla JavaScript function or Class
/**
* @class BaseClass
*/
var BaseClass = new Class({
mathify: function( value ){
return value * 2
}
})
/**
* Extends the base class and adds functionality
* @class ExtendingClass
* @extends BaseClass
*/
var ExtendingClass = new Class({
Extends:BaseClass
/**
* It does math...
*/
,mathify: function( value ){
original = this.parent( value );
return original ^ value;
}
/**
* Converts a value to it's string representation
*/
,stringify: function( value ){
return "" + value
}
});
Implements is the equivalent of Mixins. Implement takes any number of Classes / Objects, creates a single instance of each and re-implements each their members on to it parent Class
[Mi]cks`in. -n. noun; -v. verb
- To combine or mix
- A class which consists of a combinations of methods from other classes
/**
* Add simple get / set methods
* @class GetterSetter
*/
var GetterSetter = new Class({
$cache:{}
,get: function( key ){
return this.$cache[key];
}
,set: function( key, value ){
this.$cache[key] = value;
}
});
/**
* A Class that makes use of multiple inheritance
* @class ExtendingClass
* @Extends BaseClass
* @mixes GetterSetter, OtherClass
*/
var ExtendingClass = new Class({
Extends: BaseClass
,Implments:[ GetterSetter, OtherClass ]
/**
* It does math...
*/
,mathify: function( value ){
original = this.parent( value );
return original ^ value;
}
/**
* Converts a value to it's string representation
*/
,stringify: function( value ){
return "" + value
}
});
Creating new Mutators is as easy as tacking a function on a new key in the Class.Mutators namespace. You are only limited by your imagination. A classic simple might be a Mutator that allows a class to keep track of every instance it has created.
Class.Mutators.Track = function( track ){
var original_initialize
,cls;
cls = this;
if( !!track ){
// grab the origin initialize function
original_initialize = Function.from( this.prototype.initialize ) ;
}
// overload the initialize method
klass.prototype.initialize = function( ){
( klass.instances=klass.instances || [] ).push( this );
original_initialize.apply( this, arguments )
};
};
/**
* Keep a references of all of its created instances around
* @class TrackedClass
* @Extends BaseClass
* @mixes GetterSetter
*/
var TrackedClass = new Class({
Extnds:BaseClass
,Implements:[ GetterSetter ]
,initialize: function( ){
// do something fancy!
}
Track: true
,each: function( fn ){
var len = TrackedClass.instance.length
,instances = TrackedClass.instances;
// do something for each of the instances
for( var x=0; x < len; x++){
fn.call( instances[ x ], x, instances );
}
}
});
Now every time you create an instance of TrackedClass, you will be able to perform bulk operations of all of the instances that might be hanging around. Mutators are a pretty powerful hook into the Class systems creation pipeline. It will allow you to separate large chunks of repeated code out into small logical pieces and reuse them in a very simple manner.