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:
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
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]); } } };
__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.
The class should be pretty self explanatory. We can't just update the initials without changing the name, hence only a getter for initials.
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] + "."; } });
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
Pretty cool, sad it's not supported in IE, but I heard that it might be supported in IE8;)
...the creation of private methods through closures.
Update: Nathan points out that there’s also an Exposes mutator that Jan put together. This entry was posted on Thursday, December 11th, 2008 at 4:19 pm and is filed under ...