{ Additional Array Methods. }

Objectives:

By the end of this chapter, you should be able to:

  • Use some and every to iterate through an array and return a boolean.
  • Use find and findIndex to locate elements and indexes in an array.
  • Understand how to chain/combine iterators to write more complex code
  • Explain the advantages and drawbacks of using iterators versus loops
  • Determine when to use certain array methods based on the problem you are trying to solve

some

To figure out if ANY single value satisfies a condition in an array, we can use the some function. This will return true if ANY value passes a condition specified in the callback, and false if all values fail the condition.

var arr = [1,2,3,4];

var anythingGreaterThanTwo = arr.some(function(val){
    return val > 2;
});

var anyStrings = arr.some(function(val){
    return typeof val === "string";
});

anythingGreaterThanTwo; // true
anyStrings; // false

You can read more about some here.

every

To figure out if ALL values satisfy a condition in an array, we can use the every function. This will return true if ALL values pass a condition specified in the callback. If even one value fails the condition, every will return false.

var arr = [1,2,3,4];

var everythingGreaterThanTwo = arr.every(function(val){
    return val > 2;
});

var everythingLessThanFive = arr.every(function(val){
    return val < 5;
});

everythingGreaterThanTwo; // false
everythingLessThanFive; // true

You can read more about every here.

find

find was added to JavaScript in ES2015 to make it easier to find an element in an array based on some condition. This iterator will return the first value in an array that satisfies a condition (an expression that returns true in the callback).

var arr = [-3,1,8,4];
var firstValueGreaterThanTwo = arr.find(function(val){
    return val > 2;
});

firstValueGreaterThanTwo; // 8

You can read more about find here.

findIndex

To find the first index in an array that satisfies a condition (an expression that returns true in the callback) - we can use the findIndex function.

var arr = [-3,1,8,4];
var firstIndexOfElementGreaterThanTwo = arr.findIndex(function(val){
    return val > 2;
});

firstIndexOfElementGreaterThanTwo; // 2

You can read more about findIndex here

Combining Iterators

By combining iterators, you can often manipulate arrays using a sequence of very simple functions, rather than one larger, more complex loop. For example, suppose you wanted to take an array of numbers, filter out the even ones, double the remaining values, and then add everything up. We can do this by chaining three iterators together:

var arr = [1,2,3,4,5]
arr.filter(function(val){
    return val % 2 !== 0; // only keep odd numbers
}).map(function(val){
    return val * 2; // double remaining values
}).reduce(function(acc,next){
    return acc + next; // add everything up
},0) // 18

This sort of chaining helps keep your code easy to reason about, because each callback is only responsible for one thing. To make things even more readable, you could give names to the callbacks:

var arr = [1,2,3,4,5];

function isNumberOdd(val) {
    return val % 2 === 1;
}

function doubleValue(val) {
    return val * 2;
}

function sum(a,b) {
    return a + b;
}

arr.filter(isNumberOdd)
    .map(doubleValue)
    .reduce(sum,0); // 18

By keeping the code inside of our functions simple, we can reduce (no pun intended) the likelihood that we'll introduce bugs into our code, and when we come back to our code weeks or months later, it'll hopefully be easier for us to wrap our heads around.

Additional note and refactoring when using iterators

Just because JavaScript has a lot of different iterators, this doesn't necessarily mean you should always use an iterator in place of a for loop. One of the biggest advantages to using a for loop is that you can break out of the loop or continue to the next iteration using the keywords break and continue. If you try to use these keywords inside of an iterator, however, you'll get a SyntaxError.

Now that you've seen some iterators, let's highlight some situations when you might want to use one over another. If you're used to writing for loops you'll probably be most likely to use forEach, but this isn't always the best iterator for the job:

var arr = [1,2,3]

// using forEach

var newArr = [];
arr.forEach(function(val){
    newArr.push(val*2);
});

// In the above example, we're creating a new array
// with the same length as the old array. So instead
// of forEach, we can refactor to use map:

var newArr = arr.map(function(val){
    return val*2;
});
var arr = [1,2,3]

// using forEach
var newArr = [];
arr.forEach(function(val){
    if(val >= 2){
        newArr.push(val);
    }
})

// In the above example, we're creating a smaller array. 
// We're also not changing any values. So instead
// of forEach, we can refactor to use filter:

// refactor to use filter
var newArr = arr.filter(function(val){
    return val >= 2;
})

Before using an iterator, it's always good to ask whether forEach is the best candidate for the job, or whether another iterator would be more appropriate. If you're trying to manipulate values in an array to return a new array of the same length, map is probably a better choice. If you're trying to remove some elements in the array and keep others, filter is more likely the way to go. And if you're looking to take an array and output some other value (a number, a string, an object, etc.), consider whether or not you can use reduce to get the job done.

When you're ready, move on to Iterators Exercises

Continue