Are For Loops or ForEach Better in JavaScript?

Are For Loops or ForEach Better in JavaScript?

Which one you should choose, and why

Whenever I review a code, I see people keep mixing for and forEach in their code. Either they are confused, or they can’t differentiate between for and forEach. As a thumbs rule, You should always use forEach except for a few scenarios. Here in this article, I will explain when you should make those exceptions. This is valid for **Array.map** also.

Basic syntax

Before going further let’s have a quick look at both of the syntaxes.

For Loop:

for ([initialExpression]; [conditionExpression];[incrementExpression]) {  
  statement|s  
}

const array = [1, 2, 3, 4, 5];  
for (let index = 0; index < array.length; index++) {  
  console.log(array[index]);  
}

ForEach Loop:

arr.forEach(callback(currentValue[, index[, array]]) {  
  // execute something  
}[, thisArg]);

const array = [1, 2, 3, 4, 5];  
array.forEach((item) => {  
  console.log(item);  
});

Here in the above samples, Both code will print the log sequence of numbers. ForEach takes a functional approach to solving the problem. ForEach takes a function callback and execute over each value in the array. The forEach method looks more concise than the For loop. But there are cases where we need for loop, or we can say for loop is better than forEach. Let’s explore.

1. Looping to a range of values: Suppose you have to loop some code for particular times(assume 100). You can’t use forEach here. Because for ForEach you need to have an array of data. You can use Array(100).fill(0) to create an Array of data filled with 0. But it is an extra headache.

// Sum of the first 99 natural numberslet sum = 0;  
for (let index = 0; index < 100; index++) {  
  sum += index;  
}

Same code using forEach

let sum = 0;  
Array(100)  
  .fill(0)  
  .forEach((_, index) => {  
    sum += index;  
  });  

console.log(sum); // 4950

Here the complexity of the code is high( O(2n)). Since we are looping 2 times. One to fill the array and the second one to iterate the array to collect natural numbers.

2. Increment index other than 1: This is another good case, Where you should use for loop instead of forEach. It will reduce the complexity of the code.

For example, Think you have an array of data and you have to perform collect pairs of the data.

let numbers = [0, 1, 2, 3, 4, 5, 6, 7];  
let pairs = [];  

for (let index = 0; index < numbers.length; index += 2) {  
  pairs.push([numbers[index], numbers[index + 1]]);  
}

console.log(pairs); // [ [ 0, 1 ], [ 2, 3 ], [ 4, 5 ], [ 6, 7 ] ]

Notice we can skip(increment) index by any number here. If you have to do the same using the forEach loop you have to have some logic to skip the 2nd number each time.

let numbers = [0, 1, 2, 3, 4, 5, 6, 7];  
let pairs = [];

numbers.forEach((item, index) => {  
  if (index % 2 === 0) {  
    pairs.push([item, numbers[index + 1]]);  
  }  
});  

console.log(pairs); // [ [ 0, 1 ], [ 2, 3 ], [ 4, 5 ], [ 6, 7 ] ]

3. Conditional Break/Continue in a loop: Due to some reason If your code requires to conditional break loop. For loop is better to use than forEach. This is because breaking a forEach loop is pain. I have written an entire article just to explain how to break a loop.

let numbers = [0, 1, 2, 3, 4, 5, 6, 7];for (let index = 0; index < numbers.length; index++) {  
  if (numbers[index] > 5) {  
    break;  
  }  
  console.log(numbers[index]); // 0, 1, 2, 3, 4, 5  
}

Similar code if you have to write using forEach, You have to throw an error and catch it.

let numbers = [0, 1, 2, 3, 4, 5, 6, 7];const printValueTill5 = (v) => {  
  if (v % 5 == 0) {  
    **throw new Error("index is greater than 5");**  
  }  
  console.log(v);  
};  
try {  
  numbers.forEach(printValueTill5);  
} catch {}

4. Working in the chunks, split array: Another good use case could be when you have to work in the chunk of the data. So you can start index from where you leftover in the first iteration.

For example, Suppose you have to merge 2 arrays and you are not sure about the size of both arrays.

const array1 = [1, 3, 5, 7, 8, 9, 10];  
const array2 = [2, 4, 6];  
const merged = [];let index = 0;  

for (; index < array1.length && index < array2.length; index++) {  
  merged.push(array1[index]);  
  merged.push(array2[index]);  
}

// loop over array1, if left any  
for (; index < array1.length; index++) {  
  merged.push(array1[index]);  
}

// loop over array2, if left any  
for (; index < array2.length; index++) {  
  merged.push(array2[index]);  
}

console.log(merged); // [1,2,3,4,5,6,7,8,9,10]

I can’t even think of writing the same code using forEach.

5. Working with nested loop: Another challenge of a forEach loop is working with nested loops. Nesting a forEach can loop very ugly. Same time it can leads to callback hell very easily.

For Example, fill a 2D/3D array.

let matrix = [];for (let i = 0; i < 3; i++) {  
  matrix[i] = [];  
  for (let j = 0; j < 3; j++) {  
    matrix[i][j] = [i, j];  
  }  
}  

console.log(matrix);

/*  
[  
  [ [ 0, 0 ], [ 0, 1 ], [ 0, 2 ] ],  
  [ [ 1, 0 ], [ 1, 1 ], [ 1, 2 ] ],  
  [ [ 2, 0 ], [ 2, 1 ], [ 2, 2 ] ]  
]  
*/

Conclusion

Maybe working with raw for loop is tricky and error-prone. But for loop has its own place. It gives you full control over data, index and condition flow. Same time based on the above examples, We can make the assumption that whenever your work requires more interaction with the index/conditional expression. You can use for-loop. For the rest of the case use forEach for data first uses.

Thanks for appreciating my effort. It encourages me to write more and better than the previous.

“I know it has been tough but I still cheering for you.” - Anonymous

Did you find this article valuable?

Support Deepak Vishwakarma by becoming a sponsor. Any amount is appreciated!