Хватит писать циклы 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 прошлого поколения.
Чистота превыше всего! ;)