Массивы — самая используемая структура данных в JS. Однако методы высшего порядка (map, filter, reduce) могут быть менее производительными, чем обычные циклы, в критических участках кода. Разберем, когда что использовать.
Читаемость против Скорости
Методы массивов делают код декларативным и чистым.
const numbers = [1, 2, 3, 4, 5]; const squares = numbers.map(n => n * n); const evens = numbers.filter(n => n % 2 === 0);
Однако каждый метод создает новый массив и новую функцию. В цикле на 10 элементов это незаметно. В цикле на 1 000 000 элементов это может вызвать сборку мусора и лаги.
// Более производительно для больших данных
const result = [];
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 === 0) {
result.push(numbers[i] * numbers[i]);
}
}
Опасность вложенных циклов
Методы вроде find, includes, indexOf имеют сложность O(n). Если вы вкладываете их друг в друга или в map, сложность становится O(n²).
// Плохо: O(n²)
const users = [{id: 1}, {id: 2}];
const orders = [{userId: 1}, {userId: 2}];
const result = orders.map(order => {
return users.find(u => u.id === order.userId);
});
// Хорошо: O(n) с использованием Map
const userMap = new Map(users.map(u => [u.id, u]));
const resultOptimized = orders.map(order => userMap.get(order.userId));
Используйте Map или объекты для поиска по ключу, вместо перебора массива внутри другого перебора.
Мутация или Копирование
Методы push, pop, splice мутируют исходный массив. Методы concat, slice, spread (...) создают копии. В React и Redux мутация запрещена.
// Мутация (избегать в state) arr.push(1); // Иммутабельность const newArr = [...arr, 1];
Всегда проверяйте документацию метода: меняет ли он исходный массив. Это предотвратит странные баги, когда изменение в одном месте ломает данные в другом.