Перестаньте везде в JavaScript использовать Array.forEach для всех "for/of"!
Перестаньте в JavaScript бездумно использовать Array.forEach для всех "for/of"!


Array.forEach — головная боль программиста на JavaScript.

В течение некоторого времени меня беспокоило то, что люди вносят в свой код всевозможную ненужную головную боль с помощью Array.forEach. Это только усугубилось благодаря анонимным функциям, особенно болезненно загадочным и зачастую откровенно глупым и бессмысленным "Arrow Functions" Стрелочные функции. Сейчас я постоянно вижу код, в котором проблемы с масштабированием, ясностью кода и множеством других проблем возникают из-за того, что люди слишком хорошо продумывают простейшую логику кодирования.

Например, я постоянно вижу такой код в практическом применении:

 

var company = {
  name : 'Dunder Muffin',
  employees : 'Pam', 'Jim', 'Andy', 'Kelly',
  showEmployees : function() {
    this.employees.forEach(
      employee => console.log(this.name + ': ' + employee)
    )
  }
}

Простая альтернатива Array.forEach в JavaScript.

Что в этом плохого, спросите вы? Четыре обращения к функции впустую, необходимость в стрелочных функциях, чтобы обойти проблемы с масштабированием, которых вообще не должно быть, и отсутствие ясности кода JavaScript. Почему бы просто не:

var company = {
  name : 'Dunder Muffin',
  employees : 'Pam', 'Jim', 'Andy', 'Kelly',
  showEmployees : function() {
  for (var employee of this.employees) {
      console.log(this.name + ': ' + employee;
    }
  }
}

В чём проблема лишних функций при программировании?

Каждый раз, когда вы вызываете функцию, независимо от языка программирования, вы вводите много накладных расходов. Те из нас, кто все еще работает на ассемблере, понимают это, поскольку существует общий процесс, который все языки должны выполнять для вызова функции.

Обычно, (и здесь я слишком упрощаю), когда выполняется вызов функции, текущее состояние программы, включая счетчик программы, сохраняется в "стеке", (секции памяти, зарезервированной для ... ну, для сохранения вещей). Затем все аргументы / параметры / все остальное, также должны быть либо сохранены в стеке, либо должны быть установлены указатели на их значения. Только после этого счетчик программы, (указатель на то, где выполняется текущий код), может быть изменен на указатель функции для её запуска. Когда функция завершается, она должна освободить и восстановить все эти значения при возврате.

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

Поэтому Array.forEach выполняется во много раз медленнее, чем простой цикл. С "for/of" вы не жонглируете с памятью на каждой итерации, не запускаете сборку мусора, (если то, что есть в JavaScript, вообще можно так назвать), преждевременно, и, что самое главное, вы знаете, где находится ваша чертова область видимости!

Ещё один пример эффективного программирования на JavaScript.

Нечто подобное можно сделать и в устаревших браузерах. Вместо того чтобы заполнять Array.forEach и затем использовать обычную функцию - поскольку стрелочные функции не работают в IE. Можно просто:

for (
  var i = 0, employee;
  employee = this.employee[i];
  i++
) {

Предполагается, что все записи типа Array не являются "свободными ложными". Помните, что все присваивания также "возвращают" значение, с которым можно выполнять операции. Если у вас есть что-то вроде nodeList или другого массива, в котором, как вы знаете, нет записей с ложными значениями, это самый быстрый способ зацикливания.

Если бы не было возможности оперировать присваиваниями, не было бы необходимости различать i++ и ++i.

Это работает со всеми типами массивов, в отличие от .forEach, где я видел, как люди пытаются сделать типизацию своих Array-подобных структур в Array. Если у вас есть false, zero или другие свободные ложные значения, достаточно просто:

for (
  var i = 0, employee;
  undefined !== (employee = this.employee[i]);
  i++
) {

Может показаться, что это должно работать медленнее, но если вы обращаетесь к employee[i] более одного раза в вашем реальном коде, хранение в переменной будет быстрее, как и сама операция сравнения. Это та структура, которую большинство из нас ДОЛЖНО использовать на стороне клиента, и страшно представить, как многие этого не делают, или даже никогда не видели, что такое возможно.

Проблема в том, что, хотя эти разнообразные методы "старой школы" выглядят как больший объем кода, часто они таковыми не являются.

Комплексный подход к выбору инструментов программирования на JavaScript.

Серьезно, если учесть, что для серверных операций есть "for/of", если вам нужна индексация - "for by assignment", а для итерации объектов - "for/in", то Array.forEach — это неаккуратная, ненужная и вызывающая проблемы структура. Она ни в коем случае не является улучшением языка JavaScript. То же самое относится и ко многим другим способам, основанным на обратном вызове, когда люди используют их для всего, используя поливочную машину вместо пипетки.

Новое не всегда лучше.

Я НЕ говорю, что не нужно вообще никогда использовать обратные вызовы или методы типа Array.forEach! Опять же, не надо делать пустых заявлений. Правильный инструмент для правильной работы. Просто перестаньте использовать их в коротких фрагментах, которые вы не будете использовать повторно, в местах, где это создает головную боль, когда есть более чистые/простые варианты решения задачи. Думайте, прежде чем писать! Изучите все возможные способы выполнения задач, чтобы выбрать правильный, вместо того, чтобы изучать только один способ и верить, что он является ответом на все вопросы.

Есть множество случаев, когда эти различные "действия через обратный вызов" имеют смысл. У вас может быть одна и та же функция/функции, зацикленная в нескольких разных местах, поэтому статическая функция будет иметь смысл, так как накладные расходы на обратный вызов все равно будут. Но в любом случае, когда вы передаете эти данные итераторам анонимной функции? Вот когда эти методы становятся мгновенным эпическим фиаско в веб-разработке. Особенно, когда любой браузер, поддерживающий эти обратные вызовы и "стрелочные функции", также имеет "for/of".

Перевод с английского:
medium.com

Заберите ссылку на статью к себе, чтобы потом легко её найти!
Раз уж досюда дочитали, то может может есть желание рассказать об этом месте своим друзьям, знакомым и просто мимо проходящим?
Не надо себя сдерживать! ;)

Старт! Горячий старт на просторы интернета
Старт! Горячий старт на просторы интернета
Старт! Меню