The Array.every Method in JavaScript
Greetings, friends! In this tutorial, I will discuss the Array.every method in JavaScript. If you come from the Ruby programming language, it is very similar to the Enumerable#all method in Ruby. In C#, it's similar to the Array.TrueForAll method.
The Array.every
method tests whether all elements in an array pass a test as defined by a predicate. A predicate is a function that returns a boolean value. Let's look at an example.
const array = [2, 4, 6, 8, 10];
const isEven = x => x % 2 === 0;
const result = array.every(isEven);
console.log(result); // true
In the code snippet above, the isEven
callback function would be considered the predicate. We are calling the predicate callback function to test whether each element in array
is an even number or not.
Let's look at the Array.every
method's documentation more closely. According to MDN, this method can accept two parameters and returns a new array with each element being the result of the callback function.
every(callbackFn, thisArg)
Notice that this function definition is very similar to Array.forEach and Array.map.
The first parameter - callbackFn
The first parameter we pass into the every
method is a callback function, and the second parameter is thisArg
, a value to use as the this context when executing callbackFn
. It's really rare to use the second parameter. It's also an optional parameter. Let's just look at the first parameter, the callback function. We'll discuss the second parameter later.
The Array.every
method expects a callback function that has one, two, or three parameters. The second and third parameters are optional.
every((element) => { /* ... */ })
every((element, index) => { /* ... */ })
every((element, index, array) => { /* ... */ })
Using a Callback Function with One Parameter
Let's use the Array.every
method with a callback function that has one parameter.
const people = [
{ name: 'nate', books: 100 },
{ name: 'cameron', books: 50 },
{ name: 'sam', books: 20 }
];
const everyoneHaveBooks = people.every(person => {
return person.books > 0;
})
console.log(everyoneHaveBooks); // true
The code snippet above passes in an arrow function as a callback function. We could have just as easily defined our own function and pass that into the every
method instead.
const people = [
{ name: 'nate', books: 100 },
{ name: 'cameron', books: 50 },
{ name: 'sam', books: 20 }
];
function hasBooks(people) {
return people.books > 0;
}
const everyoneHaveBooks = people.every(hasBooks);
console.log(everyoneHaveBooks); // true
It's important to note that the every
method will return false
when it encounters the first failed test. This helps with performance, since we don't have to iterate through the entire array if it encounters a failed test early on in the array.
const array = [2, 4, 5, 8, 10];
const result = array.every(element => {
console.log(element);
return element % 2 === 0;
});
/* OUTPUT:
2
4
5
*/
console.log(result); // false
Using a Callback Function with Two Parameters
Let's now take a look at using the every
method with a callback function that has two parameters. The second parameter will be the index of the element of the array.
const matrix = [[2, 0, 0], [0, 2, 0], [0, 0, 2]];
const mainDiagonalEqualsOne = matrix.every((row, index) => {
return row[index] === 2;
})
console.log(mainDiagonalEqualsOne); // true
In the code snippet above, we are using the every
method to check if the matrix (an array of arrays in this case) has a main diagonal with values equal to two.
The main diagonal of a matrix is where the row index is equal to the column index. In our example, the main diagonal only has twos.
[
[2, 0, 0],
[0, 2, 0],
[0, 0, 2]
]
The every
method will iterate over every sub-array or row of the matrix. The following code is similar to what happens during each iteration of the every
method in our example.
// At index = 0:
row = [2, 0, 0];
row[0] = 2;
// At index = 1;
row = [0, 2, 0];
row[1] = 2;
// At index = 2;
row = [0, 0, 2];
row[2] = 2;
result = row[0] === 2 && row[1] === 2 && row[2] === 2;
The main diagonal of the matrix has a value of two, so the test passes during each iteration.
Using a Callback Function with Three Parameters
Next, let's try using a callback with three parameters. The third parameter will be the array we're calling the every
method on.
const result = [4, 5, 6].every((num, index, thisArray) => {
return num > thisArray.length;
});
console.log(result); // true
In the code snippet above, the parameter, thisArray
, refers to a reference to the array we're calling the every
method on. They are equivalent, which means that thisArray
will have a length of 3
. For each element in the array, we will test if the value is greater than the length of thisArray
.
You can also shorten the code snippet above by using the concise version of arrow functions.
const result = [4, 5, 6].every((num, index, thisArray) => num > thisArray.length);
console.log(result); // true
The second parameter - thisArg
We have now seen how to use the every
method with a callback function with one, two, and three parameters. However, the callback function was only the first parameter we can pass into the every
method. It also accepts a second parameter, thisArg
, which is optional.
As mentioned previously, it's rare to use this second parameter. You'll typically see it when people are implementing a complex feature or trying to support old legacy code. Let's see an example of how we might use the thisArg
parameter in the every
method.
function Player() {
this.spells = [];
this.count = 0;
this.isWhiteMage = false;
}
Player.prototype.add = function (array) {
this.spells = array;
this.count = array.length;
this.isWhiteMage = array.every((element) => {
return element.includes('cur');
}, this);
};
const nate = new Player();
nate.add(['firaga', 'thundaga', 'blizzaga']);
console.log(nate.spells); // ['firaga', 'thundaga', 'blizzaga']
console.log(nate.count); // 3
console.log(nate.isWhiteMage); // false
const flora = new Player();
flora.add(['cure', 'cura', 'curaga']);
console.log(flora.spells); // ['cure', 'cura', 'curaga']
console.log(flora.count); // 3
console.log(flora.isWhiteMage); // true
this
context and will use their parent scope instead. Assigning an arrow function to Player.prototype.add
will cause unexpected results.In the above code snippet, we are creating a Player
object by calling a function. Before JavaScript introduced the concept of classes, it was common to make objects using functions and assigning properties to them using the this keyword.
Since JavaScript is a prototypal language, we can add methods to the player's prototype. Within the Player.prototype.add
method, we are calling every
and passing a value of this
as the second parameter. In this context, the this
keyword refers to the Player
prototype. This allows us to add update properties on instances of our Player
object. In our example, we have two instances: nate
and flora
.
When we run flora.add(['cure', 'cura', 'curaga'])
, the player, "flora," will have each "spell" added to the list of spells. The spell count will be updated to match the total number of elements in the array. If all of the spells contain cur
, then the isWhiteMage
property will be set to true
.
Conclusion
This has been a comprehensive guide to the every
method in JavaScript. In summary, this method accepts similar parameters as the forEach
and map
methods. However, the every
method returns a boolean value. This boolean value will be true
if every element in the array passes the test specified by the provided function.
The every
method accepts two parameters: a callback and a value to use as the this
context when executing the callback. The callback function can accept three parameters: the current element being processed, the index of that element in the array, and the array every
was called upon. The callback function passed into the every
method is sometimes called a predicate because it is a function that returns a boolean value.