Циклы for имеют для меня особое значение. Довольно продолжительное время я активно их использовал, пытаясь уйти от циклов while. При этом неизбежно забываешь об увеличении счётчика: в циклах for это увеличение происходит автоматически. Стандартный синтаксис for, использующийся при переборе массива, надолго запечатлелся в моей памяти: for (i = 0; i < числа элементов; i++)

Объясняя начинающим разницу между циклами while и for, я всегда акцентировал внимание на том, что последние используются с определённым количеством итераций. Поэтому весь синтаксис цикла for можно отследить заранее, что приводит к меньшему числу ошибок (особенно среди начинающих) и облегчает просмотр кода в будущем, когда вы решите снова, скажем, через полгода к нему вернуться.

Я стал отходить от своей любимой итеративной структуры, отдавая предпочтение методу forEach() в JavaScript, и вам советую делать то же. В отличие от шаблонного цикла for, метод forEach() уменьшает вычислительные затраты и более чётко передаёт назначение кода. Само название метода будто взято из фразы для описания блока: делай что-нибудь для каждого элемента массива.

Что такое метод forEach()?

Как метод, встроенный в Array, forEach() появился в ECMAScript 2015, известном как ES6.

Как сказано в документации Mozilla, этот метод принимает в качестве аргумента обратный вызов. Не вдаваясь в подробности, отметим лишь одно важное обстоятельство, а именно: функция обратного вызова выполняется для каждого элемента массива. Использование forEach() лучше всего подходит для моментов, когда одна и та же операция должна выполняться на каждом элементе. У функции один обязательный параметр — значение — и три дополнительных параметра: для индекса, базового массива и присвоенного значения this.

Пример

Продемонстрируем на простом примере, как используется forEach(): определим целочисленный массив и выведем на консоль квадрат каждого значения

let nums = [1,2,3,4,5];nums.forEach(function(n) {
   console.log(n ** 2); // 1, 4, 9, 16, 25
});

Вместе с индексом

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

let nums = [1,2,3,4,5];
nums.forEach(function(n,i) {
   console.log("i: " + n ** 2);
});
/*
  0: 1
  1: 4
  2: 9
  3: 16
  4: 25
*/

Сохранение значений с помощью forEach()

А что, если нам вместо вывода на консоль надо будет сохранить результат в новой переменной? Посмотрите, в этом случае метод forEach() ничего не возвращает:

let nums = [1,2,3,4,5];
let result = nums.forEach(function(n) {
   return(n ** 2);
});
console.log(result); // неопределённый

На помощь ему здесь приходит метод map(). Если же без forEach() никак не обойтись, тогда присваивание новому массиву можно осуществить вручную.

let nums = [1,2,3,4,5];
let result = [];
nums.forEach(function(n) {
   result.push(n**2);
});
console.log(result); // [1,4,9,16,25];

Сворачивание функции обратного вызова

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

let nums = [1,2,3,4,5];

nums.forEach((n) => {
   console.log(n**2);
});

А если вы будете использовать только значение без дополнительных параметров, то можете освободить n от скобок. Если же у вас цикл состоит всего из одной инструкции, можете убрать и фигурные скобки {}.

let nums = [1,2,3,4,5];
nums.forEach(n => console.log(n**2));

А есть ли минусы?

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

let nums = [1,2,3,4,5];
for(let i=0; i<nums.length; i++) {
   nums[i] = nums[i] ** 2;
}
console.log(nums); // [1,4,9,16,25]

Эти недостатки способствуют поиску лучших решений. Одним из таких решений стал цикл for...of, появившийся в ES6 и призванный заменить forEach() как более простой и производительный.

Читайте также:


Перевод статьи Jonathan Hsu: Stop Using For Loops to Iterate Over Arrays

Предыдущая статьяСоздание интерфейсов RESTful API в Golang
Следующая статьяЗавораживающая последовательность Фибоначчи