Object.groupBy в JavaScript — группировка элементов

13 августа 2026
Автор

Антон Ларичев

Object.groupBy — статический метод, появившийся в стандарте ECMAScript 2024. Он позволяет разбить элементы любого итерируемого объекта на группы по ключу, который возвращает функция-колбэк. Результатом является обычный объект, где каждое свойство — это массив элементов одной группы.

До появления этого метода разработчики использовали Array.prototype.reduce, сторонние библиотеки вроде Lodash или писали вспомогательные утилиты вручную. Object.groupBy стандартизировал эту операцию и сделал её частью языка.

Синтаксис

Object.groupBy(iterable, callbackFn)

Параметры:

  • iterable — любой итерируемый объект: массив, Set, Map, строка и т.д.
  • callbackFn — функция, вызываемая для каждого элемента. Принимает два аргумента:
    • element — текущий элемент
    • index — индекс текущего элемента

Возвращаемое значение:

Объект без прототипа (null-прототип, как у Object.create(null)), где каждый ключ — строка или Symbol, возвращённые из callbackFn, а значение — массив элементов, для которых колбэк вернул этот ключ.

Курс по теме

Курс JavaScript с нуля

40 000+ студентов · рейтинг 4.8 · гарантия возврата 30 дней

Базовые примеры

Группировка чисел

Простейший пример — разбить массив чисел на чётные и нечётные:

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const grouped = Object.groupBy(numbers, (num) => {
  return num % 2 === 0 ? 'even' : 'odd';
});

console.log(grouped);
// {
//   odd: [1, 3, 5, 7, 9],
//   even: [2, 4, 6, 8, 10]
// }

Колбэк возвращает строку 'even' или 'odd', и метод автоматически создаёт соответствующие массивы в результирующем объекте.

Группировка по диапазону значений

const scores = [45, 72, 88, 34, 91, 60, 55, 79, 100, 23];

const graded = Object.groupBy(scores, (score) => {
  if (score >= 90) return 'A';
  if (score >= 80) return 'B';
  if (score >= 70) return 'C';
  if (score >= 60) return 'D';
  return 'F';
});

console.log(graded);
// {
//   F: [45, 34, 55, 23],
//   C: [72, 79],
//   B: [88],
//   A: [91, 100],
//   D: [60]
// }

Группировка строк

const words = ['apple', 'banana', 'avocado', 'blueberry', 'cherry', 'apricot'];

const byFirstLetter = Object.groupBy(words, (word) => word[0].toUpperCase());

console.log(byFirstLetter);
// {
//   A: ['apple', 'avocado', 'apricot'],
//   B: ['banana', 'blueberry'],
//   C: ['cherry']
// }

Группировка массива объектов

На практике чаще всего группируют массивы объектов — именно здесь Object.groupBy показывает наибольшую ценность.

Группировка товаров по категории

const products = [
  { id: 1, name: 'Ноутбук', category: 'electronics', price: 80000 },
  { id: 2, name: 'Футболка', category: 'clothing', price: 1500 },
  { id: 3, name: 'Смартфон', category: 'electronics', price: 60000 },
  { id: 4, name: 'Джинсы', category: 'clothing', price: 4000 },
  { id: 5, name: 'Наушники', category: 'electronics', price: 8000 },
  { id: 6, name: 'Кроссовки', category: 'footwear', price: 7000 },
];

const byCategory = Object.groupBy(products, (product) => product.category);

console.log(byCategory);
// {
//   electronics: [
//     { id: 1, name: 'Ноутбук', category: 'electronics', price: 80000 },
//     { id: 3, name: 'Смартфон', category: 'electronics', price: 60000 },
//     { id: 5, name: 'Наушники', category: 'electronics', price: 8000 }
//   ],
//   clothing: [
//     { id: 2, name: 'Футболка', category: 'clothing', price: 1500 },
//     { id: 4, name: 'Джинсы', category: 'clothing', price: 4000 }
//   ],
//   footwear: [
//     { id: 6, name: 'Кроссовки', category: 'footwear', price: 7000 }
//   ]
// }

Группировка пользователей по роли

const users = [
  { id: 1, name: 'Анна', role: 'admin', active: true },
  { id: 2, name: 'Борис', role: 'user', active: false },
  { id: 3, name: 'Виктор', role: 'moderator', active: true },
  { id: 4, name: 'Галина', role: 'user', active: true },
  { id: 5, name: 'Дмитрий', role: 'admin', active: false },
  { id: 6, name: 'Елена', role: 'user', active: true },
];

const byRole = Object.groupBy(users, ({ role }) => role);

console.log(byRole.admin);
// [
//   { id: 1, name: 'Анна', role: 'admin', active: true },
//   { id: 5, name: 'Дмитрий', role: 'admin', active: false }
// ]

Можно комбинировать несколько полей в одном ключе:

const byRoleAndStatus = Object.groupBy(users, ({ role, active }) => {
  return `${role}_${active ? 'active' : 'inactive'}`;
});

console.log(Object.keys(byRoleAndStatus));
// ['admin_active', 'user_inactive', 'moderator_active', 'user_active', 'admin_inactive']

Группировка транзакций по месяцу

const transactions = [
  { id: 1, amount: 500, date: '2024-01-15' },
  { id: 2, amount: 1200, date: '2024-01-20' },
  { id: 3, amount: 800, date: '2024-02-03' },
  { id: 4, amount: 300, date: '2024-02-15' },
  { id: 5, amount: 950, date: '2024-01-28' },
];

const byMonth = Object.groupBy(transactions, ({ date }) => {
  const [year, month] = date.split('-');
  return `${year}-${month}`;
});

// Подсчитать сумму по каждому месяцу
Object.entries(byMonth).forEach(([month, items]) => {
  const total = items.reduce((sum, t) => sum + t.amount, 0);
  console.log(`${month}: ${total} руб.`);
});
// 2024-01: 2650 руб.
// 2024-02: 1100 руб.

Map.groupBy vs Object.groupBy

Одновременно с Object.groupBy в ES2024 появился метод Map.groupBy. Он работает аналогично, но возвращает Map вместо обычного объекта.

const inventory = [
  { name: 'Молоко', quantity: 5 },
  { name: 'Хлеб', quantity: 2 },
  { name: 'Сыр', quantity: 0 },
  { name: 'Масло', quantity: 1 },
  { name: 'Яйца', quantity: 0 },
];

const result = Map.groupBy(inventory, ({ quantity }) => {
  return quantity > 0 ? 'inStock' : 'outOfStock';
});

console.log(result.get('outOfStock'));
// [{ name: 'Сыр', quantity: 0 }, { name: 'Яйца', quantity: 0 }]

Map.groupBy стоит выбирать в следующих случаях:

  • Ключи не являются строками — например, объекты или Symbol.
  • Важен гарантированный порядок ключей (Map сохраняет порядок вставки).
  • Результат должен передаваться в API, ожидающее Map.
const RESTOCK = Symbol('restock');
const OK = Symbol('ok');

const grouped = Map.groupBy(inventory, ({ quantity }) => {
  return quantity < 3 ? RESTOCK : OK;
});

console.log(grouped.get(RESTOCK));
// [{ name: 'Хлеб', quantity: 2 }, { name: 'Сыр', quantity: 0 }, ...]

В большинстве задач с строковыми ключами достаточно Object.groupBy — результат легче сериализовать в JSON и передать через сеть.

Сравнение с Array.prototype.reduce

До ES2024 стандартным способом группировки был метод reduce. Сравним оба подхода:

const people = [
  { name: 'Алексей', department: 'engineering' },
  { name: 'Марина', department: 'marketing' },
  { name: 'Сергей', department: 'engineering' },
  { name: 'Ольга', department: 'hr' },
  { name: 'Николай', department: 'marketing' },
];

// Старый способ — reduce
const withReduce = people.reduce((acc, person) => {
  const key = person.department;
  if (!acc[key]) {
    acc[key] = [];
  }
  acc[key].push(person);
  return acc;
}, {});

// Новый способ — Object.groupBy
const withGroupBy = Object.groupBy(people, ({ department }) => department);

Object.groupBy лаконичнее и читается значительно проще. Намерение кода очевидно с первого взгляда без анализа аккумулятора и ветвлений.

Важное отличие от reduce: объект, возвращаемый Object.groupBy, создаётся без прототипа. Это означает, что у него нет унаследованных методов вроде toString или hasOwnProperty. Такой объект безопасен для хранения данных, где ключи могут конфликтовать с методами прототипа.

const result = Object.groupBy(['foo', 'bar'], (s) => s);

console.log(Object.getPrototypeOf(result)); // null
console.log(result.toString);               // undefined

Если нужно работать с результатом как с обычным объектом, используйте Object.entries(), Object.keys() и Object.values() — они работают с null-прототипом без проблем.

Работа с итерируемыми объектами

Object.groupBy принимает любой итерируемый объект, не только массивы.

// Группировка Set
const uniqueNumbers = new Set([1, 2, 3, 4, 5, 6]);

const grouped = Object.groupBy(uniqueNumbers, (n) => n % 2 === 0 ? 'even' : 'odd');
// { odd: [1, 3, 5], even: [2, 4, 6] }

// Группировка записей из Map
const userMap = new Map([
  ['alice', { role: 'admin' }],
  ['bob', { role: 'user' }],
  ['carol', { role: 'admin' }],
]);

const groupedEntries = Object.groupBy(userMap, ([, { role }]) => role);
// {
//   admin: [['alice', { role: 'admin' }], ['carol', { role: 'admin' }]],
//   user: [['bob', { role: 'user' }]]
// }

Вложенная группировка

Object.groupBy не поддерживает многоуровневую группировку из коробки, но её легко реализовать, применяя метод рекурсивно к каждой группе:

const employees = [
  { name: 'Иван', department: 'engineering', level: 'senior' },
  { name: 'Мария', department: 'engineering', level: 'junior' },
  { name: 'Пётр', department: 'marketing', level: 'senior' },
  { name: 'Анна', department: 'marketing', level: 'junior' },
  { name: 'Кирилл', department: 'engineering', level: 'senior' },
];

// Сначала группируем по отделу
const byDepartment = Object.groupBy(employees, ({ department }) => department);

// Затем каждый отдел группируем по уровню
const nested = Object.fromEntries(
  Object.entries(byDepartment).map(([dept, members]) => [
    dept,
    Object.groupBy(members, ({ level }) => level),
  ])
);

console.log(nested.engineering);
// {
//   senior: [{ name: 'Иван', ... }, { name: 'Кирилл', ... }],
//   junior: [{ name: 'Мария', ... }]
// }

Поддержка браузерами и средами выполнения

Object.groupBy входит в стандарт ES2024 и поддерживается во всех современных средах:

  • Chrome / Edge — с версии 117
  • Firefox — с версии 119
  • Safari — с версии 17.4
  • Node.js — с версии 21

Если требуется поддержка устаревших окружений, можно написать полифил вручную:

if (!Object.groupBy) {
  Object.groupBy = function (iterable, callbackFn) {
    const result = Object.create(null);
    let index = 0;
    for (const element of iterable) {
      const key = callbackFn(element, index++);
      if (key in result) {
        result[key].push(element);
      } else {
        result[key] = [element];
      }
    }
    return result;
  };
}

Альтернативно — подключить core-js:

npm install core-js
import 'core-js/actual/object/group-by';

Типичные ошибки

Колбэк возвращает не строку и не Symbol

Если колбэк вернёт число, оно будет приведено к строке. Это работает предсказуемо, но лучше явно возвращать строку, чтобы избежать путаницы:

const arr = [1.5, 2.7, 3.1, 4.9];

// Возвращаем число — будет преобразовано в строку
const g = Object.groupBy(arr, (n) => Math.floor(n));
console.log(Object.keys(g)); // ['1', '2', '3', '4']

Ожидание мутации исходного массива

Object.groupBy не мутирует исходный итерируемый объект и не копирует элементы — он создаёт новые массивы, содержащие ссылки на те же объекты. Изменение объекта в группе отразится в исходном массиве:

const items = [{ id: 1, tag: 'a' }, { id: 2, tag: 'b' }];
const grouped = Object.groupBy(items, ({ tag }) => tag);

grouped.a[0].id = 99;
console.log(items[0].id); // 99 — изменился исходный объект

Если нужна полная копия, используйте структурированное клонирование или JSON.parse(JSON.stringify(...)).

Итог

Object.groupBy — лаконичный и читаемый способ группировки элементов любого итерируемого объекта. Метод принимает итерируемое и колбэк-функцию, возвращающую ключ группы, и строит объект, где каждый ключ содержит массив подходящих элементов.

Главные тезисы:

  • Работает с любым итерируемым: массив, Set, Map, генератор.
  • Возвращает объект без прототипа — нет конфликтов с унаследованными методами.
  • Используйте Map.groupBy, если ключи — не строки, или важен порядок вставки.
  • Заменяет громоздкие конструкции на reduce и сторонние утилиты.
  • Элементы в группах — ссылки на исходные объекты, не копии.

Чтобы глубже разобраться с объектами, массивами и современными возможностями JavaScript, приходите на курс по JavaScript на PurpleSchool.

Курс по JavaScript на PurpleSchool

Стрелочка влевоObject.keys, Object.values, Object.entries в JavaScriptОбъекты в JavaScriptСтрелочка вправо

Постройте личный план изучения Javascript до уровня Middle — бесплатно!

Javascript — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Javascript

Как работает метод trim() - JavaScriptКак работает метод toUpperCase() - JavaScriptКак работает метод toLowerCase() - JavaScriptКак работает метод substring() - JavaScriptКак работает метод startsWith() - JavaScriptКак работает метод split() - JavaScriptКак работает метод slice() - JavaScriptКак работает метод search() - JavaScriptКак работает метод replaceAll() - JavaScriptКак работает метод replace() - JavaScriptКак работает метод repeat() - JavaScriptКак работает метод padStart() - JavaScriptКак работает метод padEnd() - JavaScriptКак работает метод matchAll() - JavaScriptКак работает метод match() - JavaScriptКак работает свойство length - JavaScriptКак работает метод localeCompare() - JavaScriptКак работает метод lastIndexOf() - JavaScriptКак работает метод indexOf() - JavaScriptКак работает метод includes() - JavaScriptКак работает метод fromCodePoint() - JavaScriptКак работает метод fromCharCode() - JavaScriptКак работает метод endsWith() - JavaScriptКак работает метод concat() - JavaScriptКак работает метод codePointAt() - JavaScriptКак работает метод charCodeAt() - JavaScriptКак работает метод charAt() - JavaScript
Итератор в JavaScript
try...catch в JavaScriptError в JavaScript
Событие wheel в JavaScriptСобытие unload в JavaScriptСобытие touch в JavaScriptСобытие submit в JavaScriptСобытие scroll в JavaScriptСобытие reset в JavaScriptМетод .preventDefault() в JavaScriptСобытие mouseover в JavaScriptСобытие mouseout в JavaScriptСобытие load в JavaScriptСобытие keyup в JavaScriptСобытие keydown в JavaScriptСобытие invalid в JavaScriptСобытие input в JavaScriptСобытийная модель Event в JavaScriptОбъект события Event в JavaScriptСобытие DOMContentLoaded в JavaScriptСобытие dblclick в JavaScriptСобытие click в JavaScriptСобытие change в JavaScriptJavaScript BroadcastChannel — межвкладочное взаимодействиеСобытие beforeunload в JavaScript
Как работает метод some() - JavaScriptКак работает метод reverse() - JavaScriptКак работает метод reduce() - JavaScriptКак работает метод map() - JavaScriptКак работает метод isArray() - JavaScriptКак работает метод indexOf() - JavaScriptКак работает метод includes() - JavaScriptКак работает метод from() - JavaScriptКак работает метод forEach() - JavaScriptКак работает метод flatMap() - JavaScriptКак работает метод flat() - JavaScriptКак работает метод findIndex() - JavaScriptКак работает метод find() - JavaScriptКак работает метод filter() - JavaScriptКак работает метод every() - JavaScriptМассивы в JavaScriptArray.at, findLast, findLastIndex — новые методы массивов
Открыть базу знаний

Лучшие курсы по теме

изображение курса

Основы JavaScript

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий