each
each(iterator[, context]) -> Enumerable
The cornerstone of Enumerable
. It lets you iterate over all the elements in
a generic fashion, then returns the Enumerable
, thereby allowing chain-calling.
Iterations based on each
are the core of Enumerable
.
The iterator function you pass will be called with two parameters:
- The current element in the iteration.
- The numerical index, starting at zero, of the current cycle. This second parameter is unused (and therefore undeclared) most of the time, but can come in handy sometimes.
The optional context
parameter is what the iterator function will be bound to. If used, the this
keyword inside the iterator will point to the object given by the argument.
$break
and $continue
The usage of $continue
is deprecated. This feature will not be available in releases after Prototype 1.5 in favor of speed. Instead—since your blocks are in fact functions—simply issue a return
statement. This will skip the rest of the block, jumping to the next iteration.
Regular loops can be short-circuited in JavaScript using the break
and
continue
statements. However, when using iterator functions, your code is
outside of the loop scope: the looping code happens behind the scene.
In order to provide you with equivalent (albeit less optimal) functionality,
Prototype provides two global exception objects, $break
and $continue
.
Throwing these is equivalent to using the corresponding native statement in a
vanilla loop. These exceptions are properly caught internally by the each
method.
Examples
['one', 'two', 'three'].each(function(s) {
alert(s);
});
[ 'hello', 'world'].each(function(s, index) {
alert(index + ': ' + s);
});
// alerts -> '0: hello' then '1: world'
// This could be done better with an accumulator using inject, but humor me
// here...
var result = [];
$R(1,10).each(function(n) {
if (0 == n % 2)
throw $continue;
if (n > 6)
throw $break;
result.push(n);
});
// result -> [1, 3, 5]
each
vs. _each
If you read the main Enumerable
page, you may recall that
in order for a class to mix in Enumerable
, it has to provide the fundamental
looping code appropriate to its internal structure. This basic iteration
method must be called _each
, and it only receives one argument: the iterator
function. You’ll find further details on the main page.
Basically, Enumerable.each
wraps the actual looping code provided by _each
with:
- Support for break/continue, as described above.
- Proper maintenance and passing of the value/index arguments.
Optimized version
There is a very common use-case that will probably be better taken care of by a specialized variant: the method-calling scenario.
Say you want to invoke the same method on all elements, possibly with
arguments. You may or may not want to use the result values. This can be
achieved easily with invoke
.
This variant usually performs better than each
, since it avoids lexical
closure costs. However, it does accumulate the result values in an array,
which you might not need. At any rate, you might want to benchmark both
options in your specific use case.