Хватит писать циклы for. Пришло время использовать Underscore.

мальчик

Я НЕ БУДУ есть ветчину и яичницу!

Сколько циклов for вы написали сегодня? А за эту неделю?

var i;

for(i = 0; i < someArray.length; i++) {
  var someThing = someArray[i];
  doSomeWorkOn(someThing);
}

Ну конечно. Ничего особо страшного в этом нет. Подумаешь, код не очень приятный для глаз, и немного непонятный, а в общем, для жалоб повода нет. Но этот код ведет к еще куда более странному:

var i,
  j;

for(i = 0; i < someArray.length; i++) {
  var someThing = someArray[i];
  for(j = 0; j < someThing.stuff.length; j++) {
      doSomeWorkOn(someThing.stuff[j]);
  }
}

По шкале качества, этот пример не так уж плох, но если добавить туда ещё парочку if, начинается полное безумие.

За два года я не написал ни одного цикла for.

«О чем, черт побери, ты говоришь?»

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

Как мне это удалось?

_.each(someArray, function(someThing) {
  doSomeWorkOn(someThing);
})

Или, даже проще:

_.each(someArray, doSomeWorkOn); //спасибо, paulmcpazzi!

Это библиотека Underscore.js в действии. Она порождает чистый, простой для чтения, емкий код, без обилия переменных и эшелонов точек с запятыми. Все предельно ясно и чётко.

Вот ещё пример:

var i,
  result = [];

for(i = 0; i < someArray.length; i++) {
  var someThing = someArray[i];
  // между тем, у меня уже руки отваливаются столько кода набирать
  if(someThing.isAwesome === true) {
      result.push(someArray[i]);
  }
}

Опять же, типичный случай применения проверенных временем циклов for. Мда. Как это случается с экс-курильщиками и новообращенными веганами, даже одно упоминание о подобном коде наполняет меня праведным негодованием.

var result = _.filter(someArray, function(someThing) {
  return someThing.isAwesome === true;
})

Как и предполагает имя метода filter из Underscore.js, эти три строчки простого для парсинга кода вернули мне новый массив из всяких клёвых штук.

Или, может мне нужно выполнить определённые действия с элементами массива и получить новый, содержащий результаты этих действий?

var result = _.map(someArray, function(someThing) {
  return trasformTheThing(someThing);
})

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

var grandTotal = 0,
  somePercentage = 1.07,
  severalNumbers = [33, 54, 42],
  i; // не забудьте увеличить индекс;

for(i = 0; i < severalNumbers.length; i++) {
  var aNumber = severalNumbers[i];
  grandTotal += aNumber * somePercentage;
}

Жесть.

var somePercentage = 1.07,
  severalNumbers = [33, 54, 42],
  grandTotal;

grandTotal = _.reduce(severalNumbers, function(runningTotal, aNumber) {
  return runningTotal + (aNumber * somePercentage);
}, 0)

Сначала, этот подход казался мне странным, и я всё ещё заглядываю в документацию, когда речь идёт о методах, вроде reduce. Однако, простая осведомлённость об их существовании и категорический отказ от использования циклов for — мое основное подспорье в борьбе за качество кода. Методы, представленные выше — это лишь малая толика. Библиотека Underscore.js наполнена потрясающими средствами подобного рода, которые можно комбинировать для получения новых, поистине чудесных возможностей.

Испытание: 30 дней без циклов

Стоп.

Следующие 30 дней вы должны отказаться от циклов for. Если увидите кучку этой гадости, замените её на each или map. Сокращайте по чуть-чуть код, тут и там. И держите меня в курсе о ваших успехах.

Но, будьте осторожны. Underscore.js — это врата в функциональное программирование. Однажды попробовав, вы уже не сможете отказаться. В хорошем смысле.

Если хотите копнуть глубже, ознакомьтесь с этим руководством по функциональному программированию в JavaScript. Оно действительно очень стоящее, и займет у вас около получаса. Это описание основных принципов работы функций Underscore.js, которые я использовал выше, нечто вроде «настольной поваренной книги». Кладезь веселья для гиков.

Примечание

В качестве более производительной альтернативы Underscore.js, можете ознакомиться с lodash.

Стоит также отметить, что у современных браузеров присутствует встроенная поддержка описанных выше методов. Вполне имеют право на жизнь Array.forEach, Array.reduce и Array.map, однако для них вам, вероятно, потребуется создать фолбэк, на случай отсутствия поддержки. Для меня намного более удобным является стабильный API Underscore.js (lodash). Но вы вправе с этим не соглашаться.

Конечно же, с циклами for код исполняется быстрее. Перед тем, как оптимизировать производительность для сжатия и последующей обработки центральным процессором, я работаю над простотой восприятия кода для моей команды. Я не пишу игры или сложные, анимированные пользовательские интерфейсы. Большие проекты, десятки разработчиков - код, который и без того стремится к разрастанию и беспорядку.

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

Теперь, готовя большой список элементов в Angular, мы сосредотачиваем внимание на производительности с точки зрения центрального процессора. Но, даже так, единственная ситуация, когда мы реально зашли в тупик — это из-за не оптимизированной сетки с данными, случившаяся для телефонов на базе ОС Android прошлого поколения.

Чистота превыше всего! ;)