Проблем с кодированием и веб-сайтов предостаточно, и мне нравится решать новые проблемы, но иногда интересно настроить или улучшить старые игрушечные проблемы и придумать альтернативные творческие решения. Особенно здорово, если вы можете сделать это с еще меньшим количеством кода. Один из способов, которым я люблю бросать себе вызов, — это решать задачи с помощью рекурсии, не всегда потому, что это лучше, а просто потому, что мне нравится рекурсия. Это может привести к трудностям, потому что некоторые задачи более эффективны при использовании простого цикла while, но рекурсия все равно доставляет удовольствие. Еще одна распространенная проблема, которую я себе задаю, — это использование в решении «reduce» или «reduceRight». Дополнительный уровень абстракции почти всегда более интересен, чем стандартные циклы.

Недавно друг рассказал мне о головоломке рефакторинга, которая включает в себя обе мои любимые дополнительные задачи. Его попросили заново реализовать «reduce» в JavaScript, используя рекурсию! В довершение всего ему сказали сделать это в две строки. Что ж, мне не терпелось решить эту проблему, и ниже я разберу ее.

var reduce = function(collection, callback, startVal){
 var initVal = arguments.length > 2;
 collection.forEach(function(element){
 if(!initVal){
 startVal = element;
 initVal = true;
 }else{
 startVal = callback(startVal, element);
 }
 });
 return startVal;
 console.log(reduce([1,2,3,4,5], function(a,b){return a+b;}, 1)); // 16
};

Выше вы можете увидеть базовую реализацию сокращения. Функция проверяет, передано ли начальное значение в вызов, используя метод «.length» для объекта arguments. Если нет, начальное значение устанавливается на первый элемент в коллекции. Предоставленный обратный вызов вызывается для начального значения и каждого элемента коллекции. «startVal» переназначается возвращаемому значению обратного вызова на каждой итерации. Наконец, startVal возвращается после того, как каждый элемент в коллекции был уменьшен или свернут с помощью предоставленного обратного вызова. Теперь давайте попробуем провести рефакторинг, чтобы это было всего две строки кода и использовалась рекурсия. Для этой задачи я также буду использовать немного ES6!

let reduce = (collection, callback, startVal = 0) => {
 if(collection.length === 0) return startVal;
 return reduce(collection, callback, callback(startVal, collection.shift()));
};
console.log(reduce([1,2,3,4,5], function(a,b){return a+b;}, 1)); // 16

Тело этого решения состоит всего из двух строк кода! Мы удаляем тест начальных аргументов, используя новые «значения по умолчанию» ES6 в параметре. (Это не так полно, потому что по умолчанию он равен нулю вместо первого элемента в коллекции, но он будет работать для массива чисел) Теперь функция может начинаться с базового случая, который завершает рекурсию, когда длина коллекции равен нулю. Затем функция редукции вызывается рекурсивно, передавая коллекцию, обратный вызов и магию редукции. startVal переназначается возвращаемому значению обратного вызова в рамках рекурсивного вызова. «startVal» из предыдущего вызова является первым параметром в вызове обратного вызова, и с помощью метода .shift второму параметру присваивается первый элемент в массиве. Поскольку массивы находятся в объектах памяти, при вызове .shift массив укорачивается на единицу и перемещается на один шаг ближе к базовому варианту!

Вот и все, уменьшите в две строки, используя рекурсию и ES6! Какие еще забавные рефакторинги возможны?