Useful Utility Functions in mootools
|
|
Cory Hudson September 15, 2006
|
The new mootools JavaScript framework
has quickly impressed me with its design and usefulness. The library
was clearly written to meet real programmers’ needs while working in
JavaScript. Just take a look at some of the new utility functions and
methods it provides.
Note: This article covers functions and methods found in the Array.js and Function.js modules of mootools.
A cleaner array iterator
Mootools provides a Prototype-inspired each method that every JavaScript array inherits. Its syntax is a bit cleaner because it’s based on the Mozilla Array.prototype.forEach method. The mootools each
method allows you to pass in a second parameter as the context in which
the function will be called, allowing you to resolve the this keyword. Accomplishing this in the Prototype library involves binding the function passed to each :
var x = {sum: 0};
for (var i = 0, fixtures = []; i < 500; i++) { fixtures.push(i); }
fixtures.each(function(el, i) { this.sum+= i }.bind(x));
// x.sum = 124750
Accomplishing the same thing in mootools is just a small syntax change (the changed line is highlighted):
var x = {sum: 0};
for (var i = 0, fixtures = []; i < 500; i++) { fixtures.push(i); }
fixtures.each(function(el, i) { this.sum+= i }, x);
// x.sum = 124750
The mootools each method takes the object that will resolve to this inside the loop as the second argument.
Why should you care about this minor syntax change? Because calling bind on a function every time through a loop is going to add overhead to your code’s performance. I’ve run the previous code in Firebug with a timer and the results are very telling:
500 elements each with bind: 39ms 500 elements each: 3ms 1000 elements each with bind: 75ms 1000 elements each: 6ms
Not only is the mootools syntax cleaner, but it performs almost 10 times faster than using the bind method. Keep in mind that these examples all use mootools’ each method. If I’d used the Prototype each the code would have run even slower, but that issue has already been well-documented.
Prototype each diversion
The reason Prototype’s each loop runs so slowly is that each iteration of the loop has to run through a try/catch block in order to look for break and continue statements. If you’re using Prototype’s each and you want to break or continue in the loop, you must use the following syntax:
[1,2,3,4,5,6,7,8,9,10].each(function(el) { if (el > 7) throw $break; if (el == 4) throw $continue; alert(el); });
// Will alert "1", "2", "3", "5", "6", "7"
I’m not here to bash Prototype. It’s a great library. But I think it does need to be pointed out that its each method will run slower than traditional loops because of the design decision to incorporate a workaround for break and continue statements.
What, you’re not using break and continue statements? They can really help you cut down on loop iterations. There is no way to use break or continue in an each loop in mootools, so keep that in mind. You’ll have to use the good old-fashioned for loop for that one.
Running code at time intervals
JavaScript provides the setTimeout and setInterval functions for running code after a delay or at regular intervals. This comes in very handy for animations, but also for other GUI
functions, such as delaying hiding a menu after navigating away. The
native syntax for this can get a little verbose sometimes, so mootools
provides some utility functions as methods of every function. To run
code once after a time delay you use the delay method:
(function(){ alert("Sorry I'm late."); }).delay(5000);
This will run the function after a delay of 5 seconds. You can also run code at a regular interval using the periodical method:
var annoy = (function(){ console.log('Are we there yet?'); }).periodical(5000);
The previous code will run until the window unloads unless we clear the interval returned by periodical . Mootools provides a $clear function that will clear any time interval passed to it, whether it was created with delay or periodical :
$clear(annoy);
Just be sure to assign the periodical function to a variable, or else you won’t be able to clear it! Talk about annoying…
The second parameter to delay and periodical is the context object to call the function within, just like the each method. This can come in handy when using methods of mootools’ objects:
var xhr = new Ajax('url', {update: ajaxElement}); var $req = xhr.request.periodical(60000, xhr);
This code will create an Ajax object that calls its request object
every minute. You need to pass the Ajax object as the second argument
to periodical so the request method will run in the right context.
Cleaner object detection
Sometimes checking the type of a JavaScript object can get confusing. Everything is actually an Object, so running [1,2,3] instanceof Object returns true, even though we were checking against an array. But curisouly, running 'string' instanceof Object returns false! There’s also the typeof
function, so things can get rather confusing and frustrating in a hurry
when trying to detect object types. Mootools provides a function called
$type that will do the proper checks behind the scenes and
return a lowercase string type of the element you passed into the
function. If the type of object is not matched, $type will return false .
The types returned by $type are:
- function
- textnode
- element
- array
- object
- string
- number
- false
Try it out:
$type(function(){}); // Returns 'function'
$type(document.createElement('div')); // Returns 'element'
$type([]); // Returns 'array'
$type({}); // Returns 'object'
$type('hello world'); // Returns 'string'
$type(4); // Returns 'number'
Mootools just continues to amaze me. I’m digging through the source
code and running lots of tests to see just how the library works, so
stay tuned for more articles about this new library’s features.
|