An Introduction to Underscore.js – Part 2 Array-like collections

In part one we looked at a few of the useful array methods that Underscore provides for us. In this part of the tutorial we’re going to take a look at some of the syntactic sugar that Underscore gives us to work with array-like collection. An array-like collection is something similar to array in that it is a collection of things as opposed to a single value, but they lack some of the things that arrays possess, such as a length property.

We’ll be using the following JavaScript collections in the examples shown in this tutorial:

var myCollection = {
one: ["one", "two", "three", "four", "five"],
two: [1, 2, 3, 4, 5]
};
var myCollection2 = [
{ name: "Dan", age: 33 },
{ name: "Fred", age: 44 }
];

each()

The each() method is used to iterate over an array-like collection. It accepts a minimum of two arguments where the first argument is the collection to iterate over and the second is an iterator function which is invoked for each item in the collection. To use this method with our first test collection, we could do this:

_.each(myCollection, function(item) {
alert(item.length);
});

The arguments passed to the iterator function will vary depending on the type of object it is iterating; if it is a standard array the function will be passed the current item, the array index the item is at, and the source array. If it is an object, such as in this example, the arguments are the value of the current item, the key (or property name), and the source object.

The each() method may also accept a third argument which is the context in which the iterator function should run. This can be incredibly useful when using each() inside a callback function, as typically the value of the this object is lost inside these functions, which can be corrected by passing in the object to use as the context for this.

size()

We used the length property as the value of our alert in the previous example, which worked because the value we were checking was a proper array. I mentioned above that one of the differences between arrays and array-like collection is that the latter do not have length properties. That can be annoying can’t it? The size() method overcomes this minor irritation for us and tells us the number of items in the collection:

_.size(myCollection);

With our test object, this will result in a value of 2, which can be useful when we need to know how many items we’re dealing with, but don’t necessarily know if we’ll be working with an array or an object.

pluck()

pluck() is a super-useful method used to extract a matching property from a series of collections. This can be incredibly useful when working with something like a collection in Backbone. To ‘pluck’ each value of name from our test array, we could use this:

_.pluck(myCollection2, "name")

In this case out test collection is an array where each item in the array is an object containing two properties. The method returns an array containing the values extracted from the source collection.

filter()

The filter() method is used to filter values out of a collection that do not pass a conditional. Similar to the each() method, it accepts a collection and an iterator function (and optionally a context), and returns an array containing only those items that pass the test. To filter all items out of our second test collection whose name properties do not contain the letter a for example, we would use the method like this:

_.filter(myCollection2, function (item) {
return item.name.indexOf("a") !== -1;
});

The call back function we provide should encapsulate the logic required to test each item and should return either true or false. Items for which false are returned are not include in the array that is returned.

This method also has a polar opposite, the reject() method, which returns an array containing only those items that that fail the test.

shuffle()

Need to take a sorted collection of items and shuffle them randomly in a non-biased way? If so, the shuffle() method will be your friend. Let’s say we want to shuffle the array stored in the key one in our test object; we could simply do this:

_.shuffle(myCollection.one)

The algorithm used to shuffle the collection is based on a tried and tested method of randomly sorting a collection so you can be sure that the array that is returned will be as random as if we had drawn scraps of paper from a hat.

sortBy()

The sortBy() method allows us to perform a sort on a collection based upon specific criteria. For example, to sort the objects within our third example collection based on the name property of each object we could use the following code:

_.sortBy(myCollection3, function (item) {
return item.name;
});

The arguments used with this function have the same signature as those used with some of the other methods we’ve looked at today and consist of the collection as the first argument, an iterator function as the second and optionally, a context as the third. The iteration function simple returns the value in the collection that we want to sort by. The sort is always done in ascending order.

We can also use this method with integers, for example:

_.sortBy(myCollection3, function (item) {
return item.age;
});

In this case, the objects are sorted based on the age property instead, which will result in an array where the first item is the youngest and the last the oldest.

Summary

As we as the methods we have looked at today, there are lots of other methods that help us when working with arrays or array-like collections of data, giving us quick and easy ways to do common tasks such as filtering, sorting or shuffling.

As well as actually operating on the data in the collection in some way and returning a new modified collection, we can also test the collection using methods such as all() which returns true if all items in the collection pass a conditional test, or any() which returns true if any of the items pass a conditional.
In the next part of this tutorial we’ll take a look at some of the methods for working specifically with objects.

SHARE THIS POST
  • @quickredfox

    I’m having a hard time jumping on to the underscore train. When I need DOM/selectors and fancy ajax stuff I plug-in a jQuery and I’m happy. When I dont need jQuery I plug-in Kris Kowal’s ES5 shim https://github.com/kriskowal/es5-shim which gives me reduce, map, forEach, filter (unless the native version exists) which pretty much amounts to the methods presented here. What am I missing?

    • Danwellman

      ES5 shim seems pretty comparable to Underscore. If you ever use Backbone, Underscore is a dependency so you have to use it in that situation. I use Underscore because I use Backbone. It seems pointless learning another library, however simple, for when I want some extra functionality but don’t need Backbone…

  • Hot Belgo

    Hi, how can I create an array of arrays using underscore. I thought this would work but it doesnt

    this.field = new Array(config.width);

    _.each(this.field, function(col, colIdx, list) {
    col = new Array(config.height);
    return col;

    });