As I mentioned before, for...in would be a convenient way to enumerate arrays, if it actually worked the way you’d expect it to. Fortunately, anonymous functions make it possible to write a ForEach method that’s almost as easy to use as a proper foreach.
function ForEach(array, fn)
{
for (var n = 0; n < array.length; n++)
fn(array[n]);
}
As you can see, ForEach calls the specified function for each element of the array. So if you’d like to calculate the sum of the items in an array:
function SumArray(array)
{
var nSum = 0;
ForEach(array, function (n) { nSum += n; });
return nSum;
}
I hope you agree that this syntax is not only more compact than an explicit loop, but that it is also easier to understand. It is also less efficient, of course, but not significantly so, except in special cases where you would certainly measure to determine its impact; you could easily unravel it into a standard loop if necessary.
My preferred implementation of ForEach is slightly more complicated.
function ForEach(array, fn, objThis)
{
objThis = objThis || this;
var len = array.length;
for (var n = 0; n < len; n++)
{
var r = fn.call(objThis, array[n], n);
if (r !== undefined)
return r;
}
}
Let me explain:
- Calculating the array length outside the loop can be slightly faster.
- I pass the item index as the second argument to the called function, since that can often be useful. (The called function doesn’t need to declare it as an explicit argument if it doesn’t need it.)
- If the called function returns anything but
undefined, the loop is terminated. This allows us to simulate what would be a break statement in a normal for loop. The ForEach method returns the value returned by the called function.
- If the called function returns
undefined, the loop continues. (A function returns undefined if it gets to the end without hitting a return statement, if it hits a return statement without an expression, or if it hits a return undefined (naturally).) An explicit return statement without an expression thus simulates what would be a continue statement in a normal for loop.
- Using the
call method allows us to specify this for the called function, which can be useful when calling ForEach from an object method.
- The
objThis argument is optional, but I make sure that it is never undefined, because under Internet Explorer, the call method is slightly faster when the first argument is a valid object (passing undefined forces it to determine the “global” object itself).
For example, we can use ForEach to find an item in an array, returning the index of that item, or -1 if the item is not found.
function FindInArray(array, find)
{
var index = ForEach(array,
function (item, n)
{
if (item == find)
return n;
});
return index === undefined ? -1 : index;
}
In many cases (but not all) I have found that using ForEach is easier to write and more natural than an explicit loop. YMMV.
Update: Explicitly described how to simulate a continue; thanks to Eli for his comment.