We have been using forEach
in JavaScript for a while now, it improves the readability of our code, but what really forEach
is? Is forEach a loop in JavaScript?
1: It is not a loop
Yes you heard it, forEach
is not a loop, it is a higher order function avilable on Array
class which takes a callback as an argument and executes it with each element inside an array in sequential order.
Check out forEach
polyfill
1
2
3
4
5
6
7
8
9
if(window.Array && !Array.prototype.forEach){
Array.prototype.forEach = function(cb, thisArgs){
var items = this;
thisArg = thisArg || window;
for(var i=0; i<items.length; i++){
cb.call(thisArgs, items[i], i, items);
}
}
}
It is clear that forEach
is not a loop, it is a function, however it internally uses a for
loop to trigger the given callback with each element inside the array.
2: Can’t use break
or cotinue
statements
There is no way to stop or break a forEach
execution other than by throwing an exception, as explained earlier, forEach
is not a loop and break
or continue
statements are not part of forEach
semantics, if we use break
or continue
statemnets inside a forEach
function, it will throw a SyntaxError
.
3: It expects a synchronous function as callback
forEach
does not wait for promises to resolve.
1
2
3
4
5
6
7
8
9
10
11
12
var ratings = [5, 4, 5];
var total = 0;
var total = async function (a, b)
{
return a + b
}
ratings.forEach(async function(rating) {
total = await sum(total, rating)
})
console.log(total)
// Expected output: 14
// Actual output: 0
4: return
behaves differently
We are familiar with return
keyword and quite sure about how it behaves inside a for
loop.
Let’s write a function that returns the first even value in the collection.
1
2
3
4
5
6
7
8
9
10
11
12
function firstEven(collection){
for(var i=0; i<collection.length; i++){
if(collection[i]%2 === 0){
return collection[i];
}
}
}
var collection = [1,9,4,6,23,9,12];
var evenValue = firstEven(collection);
console.log(evenValue);
// Expected output: 4
// Actual output: 4
It worked as expected!, we got the first even value from the collection.
Let’s re-write the same function with forEach
this time.
1
2
3
4
5
6
7
8
9
10
11
12
function firstEven(collection){
collection.forEach(function(value){
if(value%2 === 0){
return value;
}
});
}
var collection = [1,9,4,6,23,9,12];
var evenValue = firstEven(collection);
console.log(evenValue);
// Expected output: 4
// Actual output: undefined
it didn’t work this time.
Explanation
A return
statement ends function execution and specifies a value to be returned to the function caller.
Let’s see how this definition fits in our scenario.
When the return
statement got executed inside the for
loop, it immediately ended the function execution (firstEven
) and returned the item associated with current iteration and we got first even number from the collection.
In case of forEach
, as stated earlier that it executes the callback function with each element in sequential order, when return
statement got executed inside a callback, it immediately ended the execution of that callback and returned the value, however callback function will keep on executing for rest of the array elements, and because we are not returning any value from the firstEven
function explicitly, it will return the default value which is undefined
.