Tuesday, 10 February, 2015 UTC


Summary

The for loop has gotten me through some pretty tough times, iterating over arrays, moving arrays into other arrays, projecting items from arrays into new arrays, transforming objects in arrays, and filtering arrays.
Arrays.
The problem with loops in JavaScript, however, is that they can only work with data available in memory, so if you're working with data in an async environment (which is a lot of the time in JavaScript) these loops aren't going to be working very well for you.
Another problem with loops is that, to me, they can get messy really quickly. One of the things I love the most about .NET is how easy it is to work with collections using LINQ. Wouldn't it be cool if JavaScript had LINQ?
Well, it doesn't... but luckily there are some array functions that can make the kinds of tasks I mentioned above super easy. Which is almost like LINQ. Let me show you how.
Get an array
Here is the array that we will be using in the following examples. It's a simple array of objects that holds the names and values of some colours, and also gives each colour an Id, because why the hell not.
var colours = [
  { id: 1, name: 'red', value: '#f00' },
  { id: 2, name: 'green', value: '#0f0' },
  { id: 3, name: 'blue', value: '#00f' },
  { id: 4, name: 'white', value: '#fff' },
  { id: 5, name: 'black', value: '#000' }  
];
Let's do stuff to it!
Loops in jQuery
Dont. You honestly don't need jQuery nearly as much as you think you do.
Iterating over an Array
I want to grab each colour object in the order they appear in the array, and output the value property.
You might be used to iterating over an array using the for loop like this...
for(var i = 0; i < colours.length; i++) {
  console.log(colours[i].value);
}
...you may not be used to using a handy function called forEach! All of these functions are called against the array itself, and require a callback function to be passed, each item is passed as an argument to your callback, like so:
colours.forEach(function (colour) {
   console.log(colour.value);
});
It may the same amount of lines of code as before, but to me this is much more readable.
Filtering Items in Arrays
I want an array that only contains the colours with an ID greater than 3. So just black and white.
We can do this using the forEach function we discussed above...
var blackAndWhite = [];
colours.forEach(function (colour) {
    if(colour.id > 3)
        blackAndWhite.push(colour);
});
This works just fine, but it can be cleaned up by using the arrays' filter method...
var blackAndWhite = colours.filter(function (colour) {
    return colour.id > 3;
});
Outputting blackAndWhite you can see that only the colour objects with an id of 4 and 5 are shown. The idea behind this method is that only objects that match the predicate you defined are returned.
Projection and Transformations in Arrays
I want to create a new array that holds only the colour values from our colours array.
Let's do it using the forEach loop first...
var colourValues = [];
colours.forEach(function (colour) {
  colourValues.push(colour.value);
});
This works just fine also, but again theres a cleaner way to perform this operation using the arrays' map method.
var colourValues = colours.map(function (colour) {
    return colour.value;
});
If we output the value of colourValues here you'll notice that it's been set to an array containing the value property of each object in the colours array. The idea here is that whatever you return from the map callback function gets pushed into the array.
Chaining it all together
Like I said above, LINQ is one of my favorite parts of the .NET framework, it makes it very easy to perform filtering and transformations on collections. Luckily, using the functions we've learned we can get similar functionality out of JavaScript. These methods can be chained together to create powerful query-like operations over arrays.
To demonstrate this let's perform both of the operations above, first I want to grab all of the colours with an ID that can be specified by the caller, and then I only want to grab the colours name. We should store this in a separate array.
We should also wrap all of this up in a nice little reusable function...
function getColourById (id) {
    return colours
      .filter(function (colour){
          return colour.id === id;  
      })
      .map(function (colour) {
          return colour.name;
      });
   };

var result = getColourById(3);
console.log(result);
Running this you will see that ["blue"] is returned from our function.
Easy, and powerful.
...and here I was using loops like a sucker.