Циклы for
имеют для меня особое значение. Довольно продолжительное время я активно их использовал, пытаясь уйти от циклов while
. При этом неизбежно забываешь об увеличении счётчика: в циклах for
это увеличение происходит автоматически. Стандартный синтаксис for
, использующийся при переборе массива, надолго запечатлелся в моей памяти: for (i = 0; i < числа элементов; i++)
…
Объясняя начинающим разницу между циклами while
и for
, я всегда акцентировал внимание на том, что последние используются с определённым количеством итераций. Поэтому весь синтаксис цикла for
можно отследить заранее, что приводит к меньшему числу ошибок (особенно среди начинающих) и облегчает просмотр кода в будущем, когда вы решите снова, скажем, через полгода к нему вернуться.
Я стал отходить от своей любимой итеративной структуры, отдавая предпочтение методу forEach()
в JavaScript, и вам советую делать то же. В отличие от шаблонного цикла for
, метод 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()
ничего не возвращает:
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
от скобок. Если же у вас цикл состоит всего из одной инструкции, можете убрать и фигурные скобки {}
.
Если коротко, то да. Какой способ написания кода ни выбери — в любом из них всегда найдутся какие-то отрицательные стороны. Один потенциальный недостаток, на который наткнулся я, заключается в невозможности изменить исходное значение в каждом индексе, а вот в цикле 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
Комментарии