Программирование

Как зациклить цвета из массива в JavaScript с map и %

Узнайте, как зациклить присвоение цветов из короткого массива к элементам длинного в JavaScript. Используйте map() и оператор % для циклического повторения: colors[i % colors.length]. Примеры с forEach, reduce и защитой от ошибок.

Как зациклить присвоение цветов из массива к элементам другого массива в JavaScript?

У меня есть массив цветов:

javascript
var colors = ["#ccc", "#333", "#666"];

И массив данных:

javascript
var data = [
 { name: "Семен" },
 { name: "Роман" },
 { name: "Николай" },
 { name: "Аркадий" },
 { name: "Жорж" }
];

Текущий код:

javascript
var result = data.map((x, i) => { return { ...x, color: colors[i] }; });

Результат:

json
[
 { "name": "Семен", "color": "#ccc" },
 { "name": "Роман", "color": "#333" },
 { "name": "Николай", "color": "#666" },
 { "name": "Аркадий", "color": undefined },
 { "name": "Жорж", "color": undefined }
]

Желаемый результат с циклическим присвоением цветов:

json
[
 { "name": "Семен", "color": "#ccc" },
 { "name": "Роман", "color": "#333" },
 { "name": "Николай", "color": "#666" },
 { "name": "Аркадий", "color": "#ccc" },
 { "name": "Жорж", "color": "#333" }
]

Как реализовать циклическое присвоение цветов с помощью map или других методов?

Проще всего зациклить присвоение цветов в JavaScript: в callback метода map используйте оператор %, например colors[i % colors.length], — это вернёт индекс 0,1,2,0,1,… и повторит цвета по кругу. Такой подход создаёт новый массив с присвоенными цветами и не меняет исходный data. Ниже — готовые примеры на map и несколько альтернатив (forEach, reduce, Array.from) с учётом крайних случаев.


Содержание


Основное решение: map() в JavaScript и оператор %

Самый короткий и читаемый вариант — заменить обращение colors[i] на colors[i % colors.length]. Пример:

javascript
const colors = ["#ccc", "#333", "#666"];

const data = [
 { name: "Семен" },
 { name: "Роман" },
 { name: "Николай" },
 { name: "Аркадий" },
 { name: "Жорж" }
];

const result = data.map((item, i) => ({ 
 ...item, 
 color: colors[i % colors.length] 
}));

console.log(result);
/*
[
 { name: "Семен", color: "#ccc" },
 { name: "Роман", color: "#333" },
 { name: "Николай",color: "#666" },
 { name: "Аркадий",color: "#ccc" },
 { name: "Жорж", color: "#333" }
]
*/

Почему так удобно: map возвращает новый массив, а % “оборачивает” индекс по длине массива цветов. Подробности про map() и его параметры — на MDN: Array.prototype.map().


Как это работает: индекс массива и длина

Вызов map((item, i) => ...) даёт вам два важных аргумента: сам элемент и его индекс i. Оператор остатка от деления % возвращает остаток от деления i на colors.length. При colors.length === 3 последовательность i % 3 для i = 0,1,2,3,4 будет: 0,1,2,0,1 — то есть цвета повторяются.

Примечание про пустой массив цветов: если colors.length === 0, то i % 0 даст NaN, и colors[NaN] вернёт undefined. Поэтому обычно добавляют защиту или значение по умолчанию:

javascript
const defaultColor = "#000";
const safeResult = data.map((item, i) => ({
 ...item,
 color: colors.length ? colors[i % colors.length] : defaultColor
}));

Если хотите проверить аргументы callback’а или посмотреть пример с индексом — полезная дискуссия есть на StackOverflow: Index inside map() function.


Альтернативные методы: forEach, reduce, Array.from (javascript методы массивов)

map — наиболее декларативный вариант для трансформации массива, но есть и другие подходы.

  1. forEach — мутирует или заполняет внешний массив:
javascript
const result = [];
data.forEach((item, i) => {
 result.push({ ...item, color: colors[i % colors.length] });
});

Минус: больше кода, побочный эффект (внешний массив).

  1. reduce — аккумулирует результат функционально:
javascript
const result = data.reduce((acc, item, i) => {
 acc.push({ ...item, color: colors[i % colors.length] });
 return acc;
}, []);

reduce полезен, если нужно делать более сложную агрегацию.

  1. Array.from — можно применить для итерабельных/array-like структур:
javascript
const result = Array.from(data, (item, i) => ({ ...item, color: colors[i % colors.length] }));

Все эти методы обсуждаются в обзорных статьях по методам массивов — например, на TheCode Media и в материалах Skillbox: Методы массивов в JavaScript.


Практические советы и подводные камни

  • Проверка на пустой массив: всегда учитывайте colors.length === 0 и задавайте fallback (например null или '#000').
  • Не мутируйте исходный массив, если хотите чистую функцию: map создаёт новый массив, forEach — нет.
  • Поддержка синтаксиса: оператор spread { ...item } требует современных сред (object spread — ES2018). Для старых сред используйте Object.assign({}, item, { color }).
  • Если нужно повторять цвета, но со сдвигом (например начать с определённого цвета), добавьте смещение: colors[(i + offset) % colors.length].
  • Для генерации случайного цвета из массива используйте colors[Math.floor(Math.random() * colors.length)], но это уже не зацикливание по индексу.
  • Производительность: % — быстрый O(1)-оператор, map — линейный по длине data. Для больших массивов проще и понятнее — map с %.
  • Типизация в TypeScript: укажите типы для data и colors, чтобы избежать ошибок доступа к индексам.

Есть ещё статьи и справочники по map и работе с индексом в callback: W3Schools — Array map и GeeksforGeeks — index inside map.


Источники


Заключение

Для циклического присвоения цветов в JavaScript лучший и самый простой вариант — использовать map вместе с оператором %: colors[i % colors.length]. Это чисто, быстро и подходит для большинства задач с javascript массивами и отображением цветов.

Авторы
Проверено модерацией
Модерация
Как зациклить цвета из массива в JavaScript с map и %