Введение
Есть много подходов к одной проблеме, и мы всегда ищем наиболее эффективное решение. Сегодня давайте сравним эффективность итерации и рекурсии.
Давайте рассмотрим простую проблему - для данного массива строк напишите функцию, которая будет использовать заглавные буквы для каждого элемента массива.
Я знаю, что все клетки вашего мозга начали прыгать, чтобы решить эту проблему. Да, у всех у нас будет разный подход к этому. Мне пришло в голову следующее. Просто и коротко.
let capArr1 = (arr) => { return arr.map((val) => val.toUpperCase()); } capArr1(["Wolverine", "Ironman"]); //["WOLVERINE", "IRONMAN"]
Итерация
Большинство из нас согласятся, что прямым решением этого было бы использование цикла и перебора элементов с заглавными буквами. Я намеренно использовал здесь новую переменную.
let capArr2 = (arr) => { let newArr = []; for (let i = 0; i < arr.length; i++) { newArr.push(arr[i].toUpperCase()); } return newArr; } capArr2(["Wolverine", "Ironman"]); //["WOLVERINE", "IRONMAN"]
Рекурсия
Некоторые заинтригованные умы хотели бы использовать рекурсию, чтобы решить эту проблему. Теперь вы, вероятно, знаете, почему я использовал новую переменную для хранения своего массива, поскольку я хочу, чтобы мои операции были одинаковыми в обоих подходах, чтобы сравнить время, затрачиваемое на выполнение этих функций.
let capArr3 = (arr) => { if (arr.length === 1) { return [arr[0].toUpperCase()]; } let newArr = capArr3(arr.slice(0, -1)); newArr.push(arr.slice(-1)[0].toUpperCase()); return newArr; } capArr3(["Wolverine", "Ironman"]); //["WOLVERINE", "IRONMAN"]
Давайте воспользуемся функцией performance.now (), чтобы измерить время, затрачиваемое каждой функцией, и увеличим размер входного массива, чтобы иметь возможность идентифицировать заметную разницу.
let veryLongArr = ["wolverine", "ironman", "captain america", "thor", "hulk", "black widow", "hawkeye", "black panther", "vision", "dr.strange", "antMan", "wasp", "spiderman", "scarlett witch", "quicksilver", "grrot", "star lord", "gamora", "rocket raccoon", "drax", "ms.marvel"] and so on.
Я создал массив из 100,00 элементов, многократно повторяя эти значения. Фух! Ну не совсем, мне помогла функция Array concat. Я создал новую функцию, которая примет одну из трех вышеперечисленных функций и найдет среднее время для выполнения 10 функций.
let avgTime = (func, veryLongArr) => { let timeArr = [], n = 0; while (n < 10) { let t1 = performance.now(); func(veryLongArr); let t2 = performance.now(); timeArr.push(t2 - t1); n++; } console.log(timeArr); return (timeArr.reduce((acc, val) => acc + val)) / 10 } avgTime(capArr1, veryLongArr); avgTime(capArr2, veryLongArr); avgTime(capArr3, veryLongArr);
Последние мысли
карта и для почти сопоставимы. Небольшая разница в производительности наблюдается для огромного набора данных. карта для меня выглядит чище и является отличным выбором, если мы уверены, что будем перебирать весь набор данных в прямом порядке, тогда как в для вы можете влиять на порядок и значение приращения.
С другой стороны, Рекурсия требует памяти, так как каждый раз она помещает адрес памяти в стек вызовов. Так что из соображений производительности лучше не использовать рекурсию. Мы можем использовать рекурсию, чтобы сделать решение более простым и читаемым.
Я бы посоветовал писать код таким образом, чтобы он был читаемым и понятным для парня, который будет поддерживать ваш код в ближайшие годы. Надеюсь, это было проницательно.
До скорого! :)