Valerio came up quite a time ago with another class mutator called Exposes. (I already wrote a post about the Binds mutator a few posts ago). I rewrote the mutator a way I think the usage is cleaner.
The Exposes mutator is about getters and setters, which means its incompatible with IE and reduces it's practical use to internal websites, experimental use, or AIR apps. The mutator converts methods named like getFoo to getters and setFoo to setters. That is myObj.foo = "bar" calls the setter and alert(myObj.foo); the getter. Note that this means you can't store the property internally under the same name, as setting the property with this.foo = newFoo; in the setter calls the setter again, which results in an endless recursion. The same is true for getters. (MDC about getters and setters)
The mutator:
Class.Mutators.Exposes = function(self, exposes){ if (!exposes) return; for (method in self) { var match = method.match(/^(get|set)([A-Z])(\w*)$/); if (match) { var prop = match[2].toLowerCase() + match[3]; self[(match[1] == 'get') ? '__defineGetter__' : '__defineSetter__'](prop, self[method]); } } };
The mutator iterates over all attributes and if one begins with set or get followed by an uppercase letter it sets it as an attribute setter or getter respectively using __defineGetter__ and __defineSetter__.
A slightly more complex Exposes mutator which accepts a list of attributes to convert is available here.
To see the usage I'll make an example. Say we have a Person with a first, last and full name. The full name being a combination of the last and first name.
var Person = new Class({ Exposes: true, initialize: function(first, last){ if (!last) { // last name not given, first argument is the full name // using the setter to set the full name this.name = first; } else { this.first = first; this.last = last; } }, getName: function(){ return this.first + " " + this.last; }, setName: function(name){ name = name.split(' '); this.first = name[0]; this.last = name[1]; }, getInitials: function(){ return this.first[0] + ". " + this.last[0] + "."; } });
The class should be pretty self explanatory. We can't just update the initials without changing the name, hence only a getter for initials.
With the Exposes mutator there is no need now to call the setter and getters by hand and we can just do things like:
var me = new Person("Jahn Kassens"); // oops, someone misspelled my first name, let's fix that me.first = "Jan"; alert(me.name); // Jan Kassens alert(me.initials); // J. K. var test = new Person("Max", "Mustermann"); alert(test.name); // Max Mustermann test.name = "John Doe"; alert(test.last) // Doe