Home » Tutorials Advanced Tutorial

Mozilla's New Array Methods

4.0/5.0 (4 votes total)
Rate:

Nicholas C. Zakas
February 13, 2006


Nicholas C. Zakas
Nicholas C. Zakas is a professional Web designer who specializes in user interface design for Web applications using JavaScript, Dynamic HTML, CSS, XML, and XSLT.


http://www.nczonline.net
Nicholas C. Zakas has written 12 tutorials for JavaScriptSearch.
View all tutorials by Nicholas C. Zakas...

When the next version of Firefox is released later this year, it will be sporting several updates to its JavaScript engine. Since JavaScript has mostly remained stagnant since the ECMA-262, 3rd edition was released several years ago, the introduction of new features is very exciting. Part of this JavaScript upgrade directly affects the Array object, which gains several new methods.

A Brief History

The Array object has had a rather sordid and controversial past. In Netscape's original JavaScript implementation, there was no Array object, and developers were forced to create their own. When the first edition of ECMA-262 was released, it formally described an Array object with some basic functionality. Both Netscape and Microsoft implemented the specification, but shortly thereafter, the third edition of ECMA-262 was finalized and introduced even more Array object methods. While Netscape rushed to implement these new methods, Microsoft lagged behind. It wasn't until Internet Explorer reached version 5.5 that the rest of the methods were added. Since that time, there have been no changes to the Array object in any browser.

The New Methods

There are seven new Array methods that can be separated into two categories, item location methods and iterative methods. The item location methods are:

  • indexOf() - returns the index of the given item's first occurrence.
  • lastIndexOf() - returns the index of the given item's last occurrence.
The iterative methods are:

  • every() - runs a function on every item in the array and returns true if the function returns true for every item.
  • filter() - runs a function on every item in the array and returns an array of all items for which the function returns true.
  • forEach() - runs a function on every item in the array.
  • map() - runs a function on every item in the array and returns the results in an array.
  • some() - runs a function on every item in the array and returns true if the function returns true for any one item.
It makes sense to discuss these methods within the context of these two categories.

 

Item Location Methods

The item location methods, indexOf() and lastIndexOf(), should be familiar to Java and .NET programmers. These methods return the index of an item's first and last occurrence an array, respectively. For example:

var aColors = ["red", "blue", "green", "orange", "purple"];
alert(aColors.indexOf("green")); //outputs "2"
alert(aColors.lastIndexOf("green")); //outputs "2"

In this example, the indexOf() method looks for the string "green" in the array aColors. Since it is the third item in the array, the method returns 2. The lastIndexOf() method also looks for "green" and returns the same value because there's only one instance of "green" in the array. If there were two or more, the results would be different:

    var aColors = ["red", "blue", "green", "orange", "purple", "green", "brown"];
    alert(aColors.indexOf("green")); //outputs "2"
    alert(aColors.lastIndexOf("green")); //outputs "5"

Here, the lastIndexOf() method returns 5 while indexOf() returns 2. This is because the lastIndexOf() method starts searching from the end of the array while indexOf() starts from the beginning.

If "green" didn't exist in the array, both methods would return -1. Using indexOf() or lastIndexOf() in this way, you can determine if the given item is in an array, such as:

    if (aColors.indexOf("brown") > -1) {
        //brown is there, act accordingly
    } else {
        //brown isn't there
    }

There is also an optional second argument to the indexOf() and lastIndexOf() methods, which is the index at which to begin searching the array. This is useful since an array can have more than one instance of a given item. For example:

    var aColors = ["red", "blue", "green", "orange", "purple", "green", "brown"];
    alert(aColors.indexOf("green")); //outputs "2"
    alert(aColors.indexOf("green", 3)); //outputs "5"

The first indexOf() call returns 2 as usual, while the second returns 5 because it is instructed to begin searching at position 3. From that position, the method continues to search forward and the next instance of "green" is in position 5. The same can be done with lastIndexOf():

    var aColors = ["red", "blue", "green", "orange", "purple", "green", "brown"];
    alert(aColors.lastIndexOf("green")); //outputs "5"
    alert(aColors.indexOf("green", 4)); //outputs "2"

In this case, lastIndexOf() is called with a second argument, specifying to start searching from position 4 and work back towards the beginning of the array. Then, the next occurrence of "green" is at position 2.

Using these methods, you can easily get all occurrences of a given item in an array by doing this:

    var aNumbers = [2, 5, 9, 2, 1, 9, 8, 9, 4, 9, 2, 9];
    var aIndices = [];
    var iPos = aNumbers.indexOf(9);

    while(iPos != -1) {
        aIndices.push(iPos);
        iPos = aNumbers.indexOf(9, iPos+1);
    }

    alert("The number 9 was found in positions " + aIndices);

This example finds the first occurrence of the number 9 in an array, then continues to look for more by using the second argument of the indexOf() method. Each index of the number 9 is added to the aIndices array so in the end, you have an array of positions.

Iterative Methods

The iterative methods all have one thing in common: they run a given function on every item in an array. These functions must be in the following format:

    function func_name(vValue, iIndex, aArray) {
        //code goes here
    }

When a function is passed into one of these iterative methods, three arguments are passed in the array item, the index of the item within the array, and the array itself. Depending on how you're using the function, this should be all the information you'll ever need.

To elaborate, let's say that you want to know if one or more of the items in an array meets some specific criteria. In this case, let's suppose that you'd like to know if any number in an array is over 90. You'd define a function like this:

    function isOver90(vValue, iIndex, aArray) {
        return vValue > 90;
    }

some() and every()

You can pass this function into the some() method, which returns true if the given function returns true for any one item in the array:

    var aNumbers = [56, 43, 23, 94, 32, 91];
    if (aNumbers.some(isOver90)) {
        alert("There's at least one number over 90");
    } else {
        alert("There are no numbers over 90");
    }

If you want to know if all numbers in the array are over 90, you need to use the every() method in the same way. The every() method returns true only if the function returns true for every item in the array:

    var aNumbers = [56, 43, 23, 94, 32, 91];
    if (aNumbers.every(isOver90)) {
        alert("All numbers are over 90");
    } else {
        alert("All numbers are not over 90");
    }

It helps to think of some() as a logical OR and every() as a logical AND. With these two methods, you can determine if there are any numbers over 90 in the array, but how can you get those numbers? This is where the filter() method comes in.

filter()

The filter() method runs a function on every item in the array and, if the function returns true, adds the value to a result array. In this way, you can extract items that meet certain criteria without doing it manually. To retrieve all numbers over 90 in the array, you can do this:

    var aNumbers = [56, 43, 23, 94, 32, 91];
    if (aNumbers.some(isOver90)) {
        var aOver90Numbers = aNumbers.filter(isOver90);
        alert("The numbers over 90 are " + aOver90Numbers);

    } else {
        alert("There are no numbers over 90");
    }

In this example, the aOver90Numbers array will contain 94 and 91, the only two numbers greater than 90 in the aNumbers array. Note that the same function, isOver90(), was used for both some() and filter() in this code. This represents the true power of these new methods.

forEach()

How often do you use a for loop to work with items in an array? Well, with forEach(), you might not ever need to write another for loop again! Okay, that may be a bit of an exaggeration, but that's the basic idea behind forEach(). Unlike the other iterative methods, this one doesn't return any value; its sole purpose is to run the same code on every item in the array. If you want to do something such as printing out all the items in an array, you could do this:

    function printOut(vValue, iIndex, aArray) {
        document.writeln(vValue + "<br />");
    }

    var aNumbers = [56, 43, 23, 94, 32, 91];

    aNumbers.forEach(printout);

This code outputs each item in the array to the page. It's important to keep in mind that you can't return a value through the function in this case, but what if you want to perform the same operation on each item in the array and get the results? That's when the map() method comes in handy.

Map()

The map() method executes a function on each item in an array and stores the results in another array. This comes in handy when you need to perform mathematical functions on entire arrays. Here's a simple example:

    function timesTwo(vValue, iIndex, aArray) {
        return vValue * 2;
    }

    var aNumbers = [4, 2, 6, 9];

    var aTimesTwoNumbers = aNumbers.map(timesTwo);

After executing, aTimesTwoNumbers contains 8, 4, 12, and 18. Note that the item in position 0 in aTimesTwoNumbers is the result of executing the function on the item in position 0 in aNumbers. This way, you can correlate information from the resulting array with the original array.

Using Object Methods

All of the examples to this point have used standalone functions passed in to the iterative methods. There is an optional second argument for all of these methods that specifies the context in which to execute the function. In plain terms, this allows you to use object methods. Suppose you have the following object:

    var oCalc = new Object();
    oCalc.base = 2;
    oCalc.factor = 5;
    oCalc.isGoodNumber = function (vValue, iIndex, aArray) {
        return (vValue % this.base == 0);
    };
    oCalc.fixValue = function(vValue, iIndex, aArray) {
        return vValue * this.factor;
    };

This object, while very simple, uses the base and factor properties to complete calculations in each method. In isGoodNumber(), a value of true is returned when the value is equally divisible by base (2); in fixValue(), the value is multiplied by factor (5). To use oCalc, you may try doing this initially:

    var aNumbers = [4, 2, 6, 9];
    if (aNumbers.some(oCalc.isGoodNumber)) {
        var aGoodNumbers = aNumbers.filter(oCalc.isGoodNumber);
        var aNewNumbers = aGoodNumbers.map(oCalc.fixValue);
    }

The intent of this example is to get all the numbers that are equally divisible by 2 and then multiply those numbers by 5. The problem here is that there is no context for the isGoodNumber() or fixValue() methods. When taken as standalone functions (which this example does), isGoodNumber() always returns false because this.base evaluates to nothing, which makes the calculation equivalent to NaN. Therefore, the if statement prevents further calculation. To fix this, just add the context object:

    var aNumbers = [4, 2, 6, 9];
    if (aNumbers.some(oCalc.isGoodNumber, oCalc)) {
        var aGoodNumbers = aNumbers.filter(oCalc.isGoodNumber, oCalc);
        var aNewNumbers = aGoodNumbers.map(oCalc.fixValue, oCalc);
    }

Now this example works as expected.

Conclusion

Mozilla's new Array methods are a welcome addition to JavaScript as a whole. With very few changes to the language (over the past few years), these methods are significant in their meaning: Mozilla believes in JavaScript and is looking towards how it can be made into a better language for Web developers. The down side is that we need to wait until Firefox 1.5 is released (now scheduled for September 2005).

In the meantime, you'll need to use a JavaScript library to emulate these new methods. I have created a library that adds the methods to the Array object in all browsers, as has Erik Arvidsson. Using either library, you'll need to make sure the JavaScript file is loaded before attempting to use any of the new methods.


Add commentAdd comment (Comments: 0)  

Advertisement

Partners

Related Resources

Other Resources

arrow