← Назад к вопросам

Задумываешься ли как улучшить обход массива

1.0 Junior🔥 201 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Оптимизация обхода массивов

Да, это важно

Я всегда размышляю о том, как оптимизировать обход массивов. Это критично для производительности, особенно когда работаешь с большими датасетами или реактивными обновлениями в React.

Способы обхода массивов

1. for loop (самый быстрый)

// Самый быстрый способ для больших массивов
const arr = new Array(1000000).fill(0);

// Быстро: простой for loop
for (let i = 0; i < arr.length; i++) {
  const item = arr[i];
  // работа с item
}

// Медленнее: forEach
arr.forEach((item, index) => {
  // работа
});

// Ещё медленнее: map
arr.map((item) => {
  // работа
});

2. Выбор метода

// Нужно преобразовать -> map
const doubled = arr.map((x) => x * 2);

// Нужно отфильтровать -> filter
const evens = arr.filter((x) => x % 2 === 0);

// Нужно найти первый -> find
const first = arr.find((x) => x > 5);

// Нужно проверить все -> every / some
const allPositive = arr.every((x) => x > 0);
const hasNegative = arr.some((x) => x < 0);

// Нужно свернуть -> reduce
const sum = arr.reduce((acc, x) => acc + x, 0);

Распространённые ошибки

1. Цепочки без необходимости

// Плохо: 3 прохода по массиву
const result = arr
  .filter((x) => x > 5)        // Проход 1
  .map((x) => x * 2)           // Проход 2
  .filter((x) => x < 100)      // Проход 3
  .map((x) => x.toString());   // Проход 4

// Хорошо: 1 проход
const result = arr.reduce((acc, x) => {
  if (x > 5) {
    const doubled = x * 2;
    if (doubled < 100) {
      acc.push(doubled.toString());
    }
  }
  return acc;
}, []);

2. Дорогие операции в цикле

// Плохо: length вычисляется каждый раз
for (let i = 0; i < arr.length; i++) { // arr.length вычисляется в каждой итерации
  console.log(arr[i]);
}

// Хорошо: сохраняем length
const len = arr.length;
for (let i = 0; i < len; i++) {
  console.log(arr[i]);
}

3. Создание новых объектов

// Плохо: создаём новый массив каждый раз
arr.filter((x) => x > 5)    // [5, 10, 15]
  .slice()                   // копия! ненужная
  .map((x) => x * 2);        // [10, 20, 30]

// Хорошо: точно знаем что нужно
arr
  .filter((x) => x > 5)
  .map((x) => x * 2);

В React — особые considerations

1. Ключи при рендере списков

// Плохо: используем index как ключ
{items.map((item, index) => (
  <div key={index}>{item.name}</div>  // key = index меняется!
))}

// Хорошо: уникальный ID
{items.map((item) => (
  <div key={item.id}>{item.name}</div>
))}

2. Фильтрация в render

// Плохо: фильтрируем в каждом render
function List({ items, filter }) {
  return (
    <ul>
      {items.filter((x) => x.type === filter).map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
} // Если items не изменился, но re-render — фильтруем снова!

// Хорошо: мемоизируем
const FilteredList = memo(({ items, filter }) => {
  const filtered = useMemo(
    () => items.filter((x) => x.type === filter),
    [items, filter]
  );
  
  return (
    <ul>
      {filtered.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
});

Оптимизация больших списков

1. Виртуализация (для 1000+ элементов)

import { FixedSizeList } from 'react-window';

function LargeList({ items }) {
  return (
    <FixedSizeList
      height={600}
      itemCount={items.length}
      itemSize={35}
      width="100%"
    >
      {({ index, style }) => (
        <div style={style}>
          {items[index].name}
        </div>
      )}
    </FixedSizeList>
  );
}

2. Пагинация

function PaginatedList({ items, pageSize = 20 }) {
  const [page, setPage] = useState(0);
  
  const start = page * pageSize;
  const paginatedItems = items.slice(start, start + pageSize);
  
  return (
    <>
      <ul>
        {paginatedItems.map((item) => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
      <button onClick={() => setPage(page - 1)}>Prev</button>
      <button onClick={() => setPage(page + 1)}>Next</button>
    </>
  );
}

Современные методы

1. flatMap вместо map + flat

// Плохо
const result = arr
  .map((x) => [x, x * 2])
  .flat();

// Хорошо
const result = arr.flatMap((x) => [x, x * 2]);

2. findIndex для поиска индекса

const index = arr.findIndex((x) => x.id === 5);
if (index !== -1) {
  arr[index] = newValue;
}

3. Set/Map для быстрого поиска

// Плохо: O(n) поиск в каждой итерации
const result = arr1.filter((x) => arr2.includes(x.id));

// Хорошо: O(1) поиск
const set = new Set(arr2.map((x) => x.id));
const result = arr1.filter((x) => set.has(x.id));

Бенчмарк простой пример

const arr = new Array(1000000).fill(0).map((_, i) => i);

// for loop: ~5ms
console.time('for');
for (let i = 0; i < arr.length; i++) {
  arr[i] * 2;
}
console.timeEnd('for');

// forEach: ~15ms
console.time('forEach');
arr.forEach((x) => x * 2);
console.timeEnd('forEach');

// map: ~20ms
console.time('map');
arr.map((x) => x * 2);
console.timeEnd('map');

Мой подход

1. Сначала пишу понятный код (map/filter/reduce)
2. Если performance проблемы — профилирую (DevTools)
3. Если нужна оптимизация — переписываю стратегически
4. Не микроптимизирую без причины

Вывод

Оптимизация обхода массивов важна, но:

  • Не преждевременно оптимизируй
  • Профилируй перед оптимизацией
  • Выбирай правильный метод (map/filter/reduce) для задачи
  • В React используй useMemo для дорогих операций
  • Для больших списков (1000+) используй виртуализацию
  • Читаемость > микрооптимизации