.includes()

We’ve touched on the great flexibility of arrays, but how do we find certain elements in them when we don't know their position in the array?

For example, let's say we're building an application that keeps track of the daily temperature throughout the week. Let's say we gather that data within an array that we can easily push data onto daily. So let's make an array temperatures and add some values to it, say 69, 82, 73, 64, etc:

const temperatures = [69, 82, 73, 64];

Traditionally, in order to figure out whether there is a given element in array we used a method called indexOf, where we could pass it the element that we want to find in the array and it would give us the index, which we know is the position of the element in the array.

Let's say using indexOf, we want to figure out whether one of the days last week there was a temperature of 82. To do that we say:

console.log(temperatures.indexOf(82)); // 1

And we get 1. So it exists and its at the index 1, great. But what if we want to know if there are was a temperature 50 last week, which we can see doesn't exist?

temperatures.indexOf(50); // -1

We get the result -1. Why is this? It's indexOf's way of telling us that it couldn't find the index of that element. As a result, it doesn't exist.

So now instead of getting the index, which we may not care about, we just want to figure out whether a value exists in the array, expressed as a boolean. And we know that we can get a boolean through a comparison of two values. So we can say

temperatures.indexOf(50) > -1;

If it's a valid index, which is from 0 to infinity, it will be greater than -1 and therefore true.

This is a bit clunky and not easily readable if you don't know that -1 means indexOf couldn't find that element. But there's a better array method for this use-case and one which has a much more logical name, includes:

Like our comparison with the result of indexOf, includes tells us true or false if a given element exists:

temperatures.includes(50); // false

This is much more readable code. So if you've been using indexOf, make the switch over to includes.

.some()

So, .includes() is a great array method, but what if we are dealing with an array full of more complex elements such as objects?

Let's say that for each temperature, we want to include more information than just the number of degrees it was. Maybe we have a value called isRecordTemp, that also tells us whether that day was a record-breaking temperature, either the highest temperature on record or the lowest day.

Let's update our temperature array accordingly with the temperature values now being called degrees:

const temperatures = [
  { degrees: 69, isRecordTemp: false },
  { degrees: 82, isRecordTemp: true },
  { degrees: 73, isRecordTemp: false },
  { degrees: 64, isRecordTemp: false },
];

If say we want to go through this array and find whether there was a record temperature, we can't use includes. Why? Because it only works with arrays whose elements are primitive values, like strings, numbers and booleans.

So now let's take a look at some more powerful array methods.

If we want to check an array of objects and see if one or more elements meet a given condition, we can use .some();

.some works like a lot of powerful array methods we'll soon use, by passing it a function. With this function, we can provide our condition. The function allows us to get access to each element in it's parameters, and in the body we can add the functionality we want.

temperatures.some(function (temperature) {});

We can name each array element which we get as the first parameter to the function whatever we like. Since .some() is iterating or going through every array element, one by one, each element will be called temperature.

Then as we mentioned, in the body, we want to see whether for each temperature object, whether it has a record breaking temperature, meaning isRecordTemp would be true. So to check for that, we can say temperature.isRecordTemp === true;

temperatures.some(function (temperature) {
  temperature.isRecordTemp === true;
});

And finally, what .some() does is return the value true or false, just like .includes. And since it's going to get that result from the function we passed to it, we need to make sure to return the result of our comparison as well. And as soon as .some() gets a return value of true, from it's inner function, it will stop and return true, that such a value exists. Otherwise, if that value doesn't exist and the condition isn't met, it will iterate through all of the elements, then return false. So if we put the result in variable called result and log it:

const result = temperatures.some(function (temperature) {
  temperature.isRecordTemp === true;
});
console.log(result); // true

And we get true. Now if we were to make isRecordTemp false for all of them, we would get false.

Now there are a couple of ways of making this shorter. Before I mention them, take a minute and try to think of one. Think back to our functions section.

The first approach I would take would be to turn the passed function into an arrow function, where we remove the parentheses around the parameters, since there's just one of them, remove the body, and the return statement, due to the implicit return:

const result = temperatures.some(
  (temperature) => temperature.isRecordTemp === true
);

And one additional way of making this shorter, is by knowing that we already have a boolean with isRecordTemp, so we don't need to compare a boolean to a boolean, so remove the comparison.

const result = temperatures.some((temperature) => temperature.isRecordTemp);

Look at how much more concise that became.

.every()

And as you might have guessed, along with some which sees if at least one element meets a certain condition, there is a method which tells us if a condition is true for every element. And such a method is called .every()

every will iterate through every single array element and only if all of them meet the provided condition will it return true, otherwise the result will be false.

Let's check to see if every temperature is not a record temperature. We can do that by replacing .some() with .every, and if we want to know if a value is false for every element, we could compare it with the boolean false:

const result = temperatures.every(
  (temperature) => temperature.isRecordTemp === false
);

Or a better way, as we've already seen, would be to use the not operator like so:

const result = temperatures.every((temperature) => !temperature.isRecordTemp);
console.log(result); // true

The result is true, there were no record temperature in this set, but if we set one of them to true, our every condition is no longer met and it returns false.

Review

So you can check for element existence with simple arrays of primitive values using the method includes. But for the same operation with complex arrays, such as those that contain objects, make use of .some() and .every() and make them more concise using arrow functions.