Цикл for vs forEach в JavaScript

Если ты новенький в JavaScript, то тебе может быть не понятна разница между использованием цикла for и метода Array.forEach.

В этой статье я сделаю сравнительный анализ этих двух способов итерирование массива.

Синтаксис

Синтаксис цикла for довольно простой, и мало чем отличается от такого цикла в других языках програмирования.

for (let counter = 0;counter<10;counter++) {
  console.log('counter=',counter);
}

Цикл for принимает 3 выражения. Первое выражение инициализация счетчика let counter = 0; выполняется до того как цыкл начнется. Второе выражение counter < 10 определяет должно ли выполнится тело цыкла. Третье выражение выполняется после каждой итерации, при обходе массива например, нужно инкрементить индекс.

Например у нас есть массив пользователей:

let users=[
    {id:1,'login':'admin',comments:[{id:1,text:'Cool!'}]},
    {id:2,'login':'js-ninja',comments:[]},
    {id:3,'login':'user',comments:[]}
    ];

И мы хотим обойти его и вывести имена пользователей

    for (let i = 0;i<users.length;i++) {
      console.log('login=',users[i].login);
    }

Если использовать цикл forEach этот код будет выглядет так:

   users.forEach(function(user,index,arr){
        console.log('login=',user.login);
   })

Метод forEach принимает функцию callback и вызывает для каждого элемента массива.
Так в чем же разница между for и forEach()?

1. Увеличевается читаемость кода

Два способа позволяют обойти массив, но большинстве случаев я использую forEach. В пример выше используются только один уровень вложенности, и код более-менее читаем, но, если мы добавим еще один цикл for, время на понимание кода увеличится.

for (let i = 0;i<users.length; i++) {
    for (let j = 0;j<users[i].comments.length; j++) {
      console.log(user[i].comments[j]);
      }
  }

Теперь появился второй счетчик цикла, за которым нужно следить, в таком коде очень легко сделать ошибку, к счастью forEach решает эту проблему

    users.forEach(user=>{
        user.comments.forEach(comment=>console.log(comment))
    })

2. Меньше ошибок на единицу (off-by-one error)

Ошибка неучтённой единицы — логическая ошибка в цикле или нарушения граничных условий, например, выход за пределы массива. Её можно произвести, изменив одно выражение из предыдущих примеров

    for (let i = 0; i<=users.length; i++) {
      console.log('login=',users[i].login);
    }

При попытке выполнения произойдет ошибка: TypeError: Cannot read property ‘login’ of undefined. Метод forEach сам следит за индексами, по тому такая ошибка не возможна при его использовании.

3. Преждевременное прерываие работы

Единственным случаем где цикл for удобнее метода forEach есть ситуация если по какой-то причине нужно остановить обход массива, например, если был найден нужен пользователь, и не имеет смысла проверять других.
Остановка выполнения цикла делается выражением break;

    function findUser(users,login){
      let user=null;
      for (let i = 0;i<users.length; i++) {
        if(user[i].login===login){
            user=user[i];
            break;
        }
      return user;
      }
    }

Стоить заметить что в ES6 появился новый метод find() которые устраняет этот недостаток forEach()

Заключение

В этой статье я не описал все возможные использования цикла for и метода forEach, но рассмотрел наиболее используемые. Также я не отметил эффективность, как показали тесты цикл for быстрее, но лучше не стоит делать преждевременную оптимизацию вашего приложения