JavaScript: Ways to Loop Over Arrays
There are surprisingly many ways to iterate over arrays in JavaScript! This post compares a few popular methods, including the simple but deceptive for..in
loop, the tried and true for
loop, and the functionally-influenced Array.map
and Array.every
.
for (var i in myArray)
The for...in
loop entices you with its simple syntax, but can sometimes yield unexpected results. It loops over all of an array’s properties, even those that it inherits from Object
or from its prototype. The for..in
loop also isn’t guaranteed to loop over the array in any particular order, so it can’t be used in cases when order matters.
In the example below, for...in
prints out a bonus property that’s been defined on the array’s prototype.
var myArray = ["a", "b", "c", "d"];
Array.prototype.eee = console.log("hey");
for (var i in myArray) {
console.log(i);
}
//0
//1
//2
//3
//eee
Array.forEach and Array.map
Array.forEach
executes a callback function for every element of an array. Unlike the for..in
loop, Array.forEach
only runs the callback on an array’s indices and doesn’t include non-index properties. It also loops over the array in ascending order, as you would expect.
forEach
has one drawback: you can’t break out of it. So it’s only useful when you want to apply some operation to every element of an array. If you only want the callback applied to certain elements, you can use Array.some
or Array.every
.
myArray = [1,2,3,4,5];
myArray.forEach(function(value, index, array){
if (element === "c") { break; }
})
//Illegal break statement
Another thing that’s interesting to note is that forEach
can’t be used to mutate the underlying array, although it can be used to alter properties on objects inside the array.
For example, the array below doesn’t change, even when the forEach
callback is used to increment each of its values.
myArray = [1,2,3,4,5];
myArray.forEach(function(value, index, array){
array[index] = value++;
})
console.log(myArray);
//[1,2,3,4,5]
Below, forEach
successfully increments the property a
on every object in myArray
.
myArray = [{"a": 1}, {"a":2}];
myArray.forEach(function(value, index, array){
value.a++;
})
console.log(JSON.stringify(myArray));
Array.map
is similar to Array.forEach
. It applies a function to every element of an array. break
statements are illegal, just as in forEach
. The only significant difference is that Array.map
returns a completely new array.
Array.every and Array.some
Array.every
and Array.some
are similar – the former can be used to test whether every element of an array satisfies some condition, while the latter tests whether at least one element satisfies that condition.
One advantage of using either Array.every
or Array.some
is that these methods automatically break when an element is found that doesn’t meet the condition (for Array.every
) or that does meet the condition (for Array.some
). In addition to being more semantically precise, they can save you time.
The code below uses Array.every
to test whether every element of an array is even. It stops running after seeing the third element (5), because that element is odd.
function isEven(element, index, array) {
console.log(element);
return (element % 2 == 0);
}
[2,4,5,8].every(isEven);
//prints "2", "4", "5"
for (var i = 0; i < myArray.length; i++)
The classic for
loop seems both foolproof and more versatile than the prior methods. Using the for
loop ensures:
- looping over the array’s elements in ascending order
- the ability to break out of the loop
- exclusion of non-index properties set on Array.prototype or Object
You can use it to loop over every element of an array, or you can break
as soon as some condition is met. You can use it to mutate an array in place, or have it set the elements of an entirely new array.
//The old-school `for` loop: tried and true!
var myArray = ["a", "b", "c", "d"];
for (var i = 0; i < myArray.length; i++) {
console.log(myArray[i]);
}