Given the Object-Oriented nature of the MooTools framework, code repetition is something that is long forgotten (or should be) in the scripts your write. With the avoidance of code repetition comes code reusability, which results in your website being easier to read, extend and maintain, and your scripts smaller in size.
At this point there’s no doubt in anyone’s mind that DRY is a principle we should stick to. However, let’s examine how to achieve this in the right way.
Natives extension
A script, no matter its purpose, deals with various native objects all the time. These may be native types, such as Strings, Arrays, Objects, Numbers, or objects that are not native to the language but are to the browser rendering engine, such as HTMLElement.
MooTools, as you already know, empowers us to extend these Natives really easily. To add a repeat() method to a String, this is all it takes:
String.implement({
repeat: function(times){
return new Array(times + 1).join(this);
}
});
This is one of the pillars of code reusability within MooTools code. But, as I’ll explain later, it can be misused.
Self-invoking functions
Probably the most natural and straightforward way of avoiding code repetition is defining a function. The code above could have been written as:
function repeat(str, times){
return new Array(times +1).join(str);
}
A downside of the snippet above is the pollution of the global namespace. The function repeat would be available to all your scripts within the window you execute it in, potentially colliding with other functions. Or making it harder to maintain when another programmer comes along and writes another repeat function, which may even do something different.
That’s when self-invoking functions come to the rescue. As you already know, the local variables defined within a function are only available to that context. If you decide to use functions instead of extending a native, this is the smart way to do it:
// we wrap our code in a self-invoking function
(function(){
// local function within this context
var repeat(str,times) = function(){
// ...
});
// notice we don't use var here, we want the Car class to be globally available
Car = new Class({
run: function() {
var a = repeat('test', 20);
}
});
ConvertibleCar = new Class({
Extends: Car,
display: function() {
var b = repeat('some string', 20);
}
});
})();
// the repeat() we defined before is no longer accessible here
When to use which method
First of all, you might be wondering why you’d go through the trouble of defining a function within a sub-context if you could have extended String in the first place. That’s valid reasoning, but only because of the nature of the example.
If you’ve been writing MooTools code for a long time, maybe sometimes you found yourself polluting your own Natives, by extending them with functions that added little reusability value. An example:
Element.implement({
doSomethingSoSpecificThatIevenFindItHardToName: function(){
// ...
}
});
Sometimes extending the natives just doesn’t feel right, specially if it’s for a logic you repeat several times but only within a class or subset of classes, and it doesn’t award a public method within your class. That’s when a function wrapped in a self-invoking function described above is best suited.
To finalize, let’s see a real-world example that contrasts these two approaches, taken from the MooTools Core.
(function(){
var walk = function(element, walk, start, match, all, nocash){
// internal dom walking logic
};
Element.implement({
getPrevious: function(match, nocash){
return walk(this, 'previousSibling', null, match, false, nocash);
},
getAllPrevious: function(match, nocash){
return walk(this, 'previousSibling', null, match, true, nocash);
},
getNext: function(match, nocash){
return walk(this, 'nextSibling', null, match, false, nocash);
},
getAllNext: function(match, nocash){
return walk(this, 'nextSibling', null, match, true, nocash);
},
getFirst: function(match, nocash){
return walk(this, 'nextSibling', 'firstChild', match, false, nocash);
},
// ...
});
})();
As you can see, it extends Element with methods that you reuse a lot, and that even MooTools utilizes in its other components. However, there’s no point in making the walk function available to the rest of the Core, let alone your scripts, since it’s used in a very specific part which deals with the DOM manipulation. Its only purpose is avoiding code repetition in the several methods it implements to Element.
if ( comments_open() ) { ?>
22 Comments
I noticed a lot of the Mootools core was re-written with these self-invoking functions in 1.2. Is the “self-invoking” part a label you came up with? They are similar to enclosures. In fact when I first saw it in 1.2 I thought it was a clever way of creating private functions with Javascript. Good post.
I read it once or twice, I don’t think it’s a very popular term though. But it is indeed more clear than just saying ‘closure’, which is a broader concept.
So we can move the clouds huh? Pretty cool.
Great post. I just recently extended a native (String.keyValToHash) and I love the simplicity.
How does using String.implement({}); Differ from prototyping directly to the string obj?
@aeron:
that’s because they *are* closures. when I read “self invoking” I thought we was speaking about using arguments.callee() until I read the code.
Good article.
@EmEhRKay: using (String|Array|etc).implement doesnt override existing methods (for example the native Array.forEach and add’s the ‘generics’ to the Native, i.e. you could use String.repeat(“Moo”, 3); to get “MooMooMoo” after the snippet on the top of the article.
Also this closure works magic for “loops methods” (those you run for many dom elements), since you can define the function and call it once.
Good point with the article.
What about _”immediately executed anonymous function”_ ?
Great article!
Pingback: Gathering of Thoughts » Blog Archive » JavaScript RegExp based highlighting for MooTools and jQuery
Pingback: Gathering of Thoughts » Blog Archive » JavaScript RegExp based highlighting for MooTools and jQuery
Pingback: JavaScript RegExp based highlighting for MooTools and jQuery | BYOHosting.com Blogs
Pingback: MooTools Tutorials and Resources Round-Up « Tech7.Net
Pingback: MooTools Tutorials and Resources Round-Up - Programming Blog
Pingback: MooTools Tutorials and Resources Round-Up » Shai Perednik.com
Pingback: AMB Album » MooTools Tutorials and Resources Round-Up
Pingback: Shopping Mall » MooTools Tutorials and Resources Round-Up
Pingback: Advertisers Blog » MooTools Tutorials and Resources Round-Up
Pingback: MooTools国外的教程和资源大集合 | CssRainBow.cn
Pingback: A word about MooTools- Anastacia
Pingback: MooTools国外经
Pingback: Geek is a Lift-Style. »Archive » MooTools Tutorials and Resources Round-Up
Pingback: Welcome to Iqin ' s blog − MooTools国外经典实例与教程大集合