As shown above, there are several ways to iterate over an array.
for .. in
for(var i in arr) { console.log("Property: " + i); console.log("Value: " + arr[i]); }
This is not an array iteration method. This is a method of iterating over an object property. Just because arrays are also objects, it almost works, but you get things other than the elements of the array, such as the length
property and any properties you could add to the object.
for( ; ; )
for(var i = 0; i < arr.length; i++) { console.log("Index: " + i); console.log("Value: " + arr[i]); }
This is a classic C-style for
loop to iterate over an array (slightly adapted for Javascript, since the array can tell you about its length, while you need to track this yourself in C). This is probably what you want.
.forEach(callback, this)
arr.forEach(function(val, ind, ar2) { console.log("Index: " + ind); console.log("Value: " + val); console.log("Array: " + ar2); console.log("this: " + this); }, optionalThisObject);
This is a functional style loop through an array. You call the forEach
method of the array and pass it a function with 1-3 arguments. The first argument is the allowed value of the array, the second argument is the index in which it was found, and the third argument is a reference to the entire array. Usually you only need the first argument, sometimes the second, and rarely the third.
You can also pass a second forEach
argument, which is the object your function should think of as this
. The use of such functions is more esoteric, but basically, if instead of an anonymous function you write it as a named function that performs some operation on the array and writes the result to the "parent" object, then you can select the "parent" object at run time by specifying what it is when you call forEach
.
map, reduce, filter, every, some, reduceRight
Ordinary iterative templates are given proper names in functional programming, which makes the code shorter, but requires a little more prior knowledge to understand what is happening. They are still very useful constructs that can be chained to compress dozens of lines into a handful.
var newArr = arr.map(function(val, ind, ar2) { return val*ind; }, optionalThisArg);
map
looks a lot like forEach
, but it takes the return value of each iteration through the array and uses it to build a new array. This allows you to convert data using very few lines of code (and the future abbreviated anonymous ECMAScript 6 function should only do this on one line).
var newVal = arr.reduce(function(prev, curr, ind, ar2) { return prev+curr; }, initial);
reduce
moves the array from left to right (from 0 to length-1) and takes a function that combines values โโtogether. prev
is the value returned by the previous iteration through the function (or the initial
value), curr
is the value in the current ind
ex array, and ind
and ar2
should make sense by now. This reduces the entire array to a single value, allowing you to produce a total, or an average, or something else. (It can also be used in map
to reduce a two-dimensional array of arrays into one array, for example.)
reduceRight
simply reduce
, but from right to left (length from 1 to 0).
var newArr = arr.filter(function(val, ind, ar2) { return val > ind; }, optionalThisArg);
filter
looks like map
and forEach
and creates a new array like map
, but the length of the new array is probably not the same as the length of the old array. filter
assumes that the boolean function is returned by the function that it passed. If the boolean value is true
, the value is placed in a new array, if false
skipped. As the name suggests, filter
filters out data that you don't want in your array.
var newBool = arr.every(function(val, ind, ar2) { return val > ind; }, optionalThisArg); var newBool2 = arr.some(function(val, ind, ar2) { return val > ind; }, optionalThisArg);
every
and some
look very similar to filter
, but they return booleans, not a filtered array. With every
it returns true
if each element passes the test, and false
otherwise; and some
returns true if any element passes the test and false
otherwise. You do not see that they are used so often, but they make sense in situations where you need the whole array if some element passes the test or you do not need an array if any element did not pass the test. (Thus, it can be used in filter
for an array of arrays, for example.)
Upcoming ES6 Standard: for .. of
Like for .. in
, for .. of
iterates through a set of object properties, not array indices, but you may find this useful.
for(var i of Obj) { console.log("Value: " + i); }
for .. of
skips the name of the property and immediately jumps to the value of the property, so you don't need to have the ugly Obj[i]
everywhere in your code. Not a single browser (which I know) has yet implemented.
Firefox extension not accepted by ECMA, but only available for Firefox: for each .. in
for each(var i in Obj) { console.log("Value: " + i); }
This is the Mozilla syntax suggested for for .. of
initially, and you can use it in Firefox right now, but I really don't recommend it.
Array non-therapy, but related: Object.keys()
If you find the iteration of the functional style of an Array object beautiful, but want you to be able to apply it to objects, this is the method for you.
var newArr = Object.keys(Obj);
This method creates an array of strings, where each row is the key of the source object.
Functional style example
So, let's say we want to get the average value of the absolute value of all the numerical values โโfor the object. (Why? I have no idea, it's just a good example to emphasize these cool features.) First, do it for real:
var average = 0, j = 0; for(var i in Obj) { if(!isNaN(Obj[i]) { j++; average += Math.abs(Obj[i]); } } average /= j;
This is not so bad, but now we have two variables in our area, average
and j
. Maybe we needed average
, but after this calculation we don't care about j
. Consider the functional version:
var average = Object.keys(Obj).filter(function(val) { return !isNaN(Obj[val]); }).map(function(val) { return Math.abs(Obj[val]); }).reduce(function(prev, curr, ind) { return (prev*ind + curr) / (ind + 1); }, 0);
In this case, we get an array of keys and filter out the keys with a non-numeric value, then match the array of the remaining keys to an array of numbers that are all positive, and then calculate the average value of c (using the moving average equation), and we say that it starts with the average value zero.
If we rewrite the above functional code using ECMAScript 6 syntax of anonymous functions with highlighting arrow (not yet implemented by browsers), we get even less:
var average = Object.keys(Obj) .filter(val => !isNaN(Obj[val])) .map(val => Math.abs(Obj[val])) .reduce((prev, curr, ind) => (prev*ind + curr) / (ind + 1), 0);
And it just looks amazing, right?
conclusions
If you adhere to the imperative style:
for(var i = 0; i < arr.length; i++) { console.log("Hours: " + arr[i]); }
If you go with a functional style:
console.log(arr.reduce(function(prev, curr) { return prev + "Hours: " + curr + "\n"; }, ""));
The functional style allows you to write really powerful code, especially when the new syntax for the anonymous bold arrow function is added.