Кратко
СкопированоСтатический метод group
группирует элементы итерируемого объекта, опираясь на переданную колбэк-функцию. Она должна возвращать ключ группы, в которую стоит положить текущий элемент. Object
сгруппирует элементы в новый объект, а Map
— в новую Map.
Пример Object.groupBy()
Скопированоconst colors = [ { value: '50% 0.2 12', name: 'oklch' }, { value: '198, 35, 109', name: 'rgb' }, { value: '55% 0.2 0', name: 'oklch' }]const groupedColors = Object.groupBy(colors, (color, index) => color.name === 'oklch' ? 'easyToUnderstand' : 'hardToUnderstand')console.log(groupedColors)/*{ easyToUnderstand: [ { value: '50% 0.2 12', name: 'oklch' }, { value: '55% 0.2 0', name: 'oklch' } ], hardToUnderstand: [ { value: '198, 35, 109', name: 'rgb' } ]}*/
const colors = [ { value: '50% 0.2 12', name: 'oklch' }, { value: '198, 35, 109', name: 'rgb' }, { value: '55% 0.2 0', name: 'oklch' } ] const groupedColors = Object.groupBy(colors, (color, index) => color.name === 'oklch' ? 'easyToUnderstand' : 'hardToUnderstand' ) console.log(groupedColors) /* { easyToUnderstand: [ { value: '50% 0.2 12', name: 'oklch' }, { value: '55% 0.2 0', name: 'oklch' } ], hardToUnderstand: [ { value: '198, 35, 109', name: 'rgb' } ] } */
Пример Map.groupBy()
СкопированоМетод Map
будет полезен, если нам в качестве ключей нужно использовать типы, которые не могут быть ключами объекта. Например, другие объекты:
const users = { 1: { id: 1, firstName: 'Василий', lastName: 'Пупкин', email: 'vasya@pupkin.person' }, 2: { id: 2, firstName: 'Анна', lastName: 'Иванова', email: 'anna@ivanova.person' }, 3: { id: 3, firstName: 'Игорь', lastName: 'Сидоров', email: 'igor@sidorov.person' }}const orders = [ { id: 1, customerID: 1, price: 1500, goods: ['Молоко', 'Хлеб'] }, { id: 2, customerID: 2, price: 2500, goods: ['Хлеб', 'Яйца', 'Сыр'] }, { id: 3, customerID: 1, price: 3000, goods: ['Сыр', 'Картофель'] }, { id: 4, customerID: 3, price: 1800, goods: ['Молоко', 'Картофель'] }, { id: 5, customerID: 2, price: 1200, goods: ['Хлеб', 'Сыр'] }]const userOrders = Map.groupBy(orders, order => users[order.customerID])for (const [user, orders] of userOrders) { console.groupCollapsed(`${user.firstName} ${user.lastName}`) for (const order of orders) console.log(`Заказ #${order.id}: ${order.goods.join(', ')} на сумму ${order.price} руб.`) console.groupEnd()}/*Василий Пупкин Заказ #1: Молоко, Хлеб на сумму 1500 руб. Заказ #3: Сыр, Картофель на сумму 3000 руб.Анна Иванова Заказ #2: Хлеб, Яйца, Сыр на сумму 2500 руб. Заказ #5: Хлеб, Сыр на сумму 1200 руб.Игорь Сидоров Заказ #4: Молоко, Картофель на сумму 1800 руб.*/
const users = { 1: { id: 1, firstName: 'Василий', lastName: 'Пупкин', email: 'vasya@pupkin.person' }, 2: { id: 2, firstName: 'Анна', lastName: 'Иванова', email: 'anna@ivanova.person' }, 3: { id: 3, firstName: 'Игорь', lastName: 'Сидоров', email: 'igor@sidorov.person' } } const orders = [ { id: 1, customerID: 1, price: 1500, goods: ['Молоко', 'Хлеб'] }, { id: 2, customerID: 2, price: 2500, goods: ['Хлеб', 'Яйца', 'Сыр'] }, { id: 3, customerID: 1, price: 3000, goods: ['Сыр', 'Картофель'] }, { id: 4, customerID: 3, price: 1800, goods: ['Молоко', 'Картофель'] }, { id: 5, customerID: 2, price: 1200, goods: ['Хлеб', 'Сыр'] } ] const userOrders = Map.groupBy(orders, order => users[order.customerID]) for (const [user, orders] of userOrders) { console.groupCollapsed(`${user.firstName} ${user.lastName}`) for (const order of orders) console.log(`Заказ #${order.id}: ${order.goods.join(', ')} на сумму ${order.price} руб.`) console.groupEnd() } /* Василий Пупкин Заказ #1: Молоко, Хлеб на сумму 1500 руб. Заказ #3: Сыр, Картофель на сумму 3000 руб. Анна Иванова Заказ #2: Хлеб, Яйца, Сыр на сумму 2500 руб. Заказ #5: Хлеб, Сыр на сумму 1200 руб. Игорь Сидоров Заказ #4: Молоко, Картофель на сумму 1800 руб. */
Как пишется
СкопированоObject
или Map
, где:
items
— итерируемый объект, например, массив;callback
— колбэк-функция. В неё будут передаваться два аргумента:Fn element
— текущий элементitems
;index
— индекс текущего элемента.
callback
должна вернуть ключ, по которому элемент будет добавлен в группу. В случае Object
ключом будет строка или символ, в случае Map
— любой тип данных.
- Chrome 117, поддерживается
- Edge 117, поддерживается
- Firefox 119, поддерживается
- Safari 17.4, поддерживается
На практике
Скопированосоветует Скопировано
Object
можно использовать как замену аналогичному методу из популярной, но уже устаревшей библиотеки Lodash.
- _.groupBy([6.1, 4.2, 6.3], Math.floor)+ Object.groupBy([6.1, 4.2, 6.3], Math.floor)- _.groupBy(['one', 'two', 'three'], 'length');+ Object.groupBy(['one', 'two', 'three'], word => word.length)
- _.groupBy([6.1, 4.2, 6.3], Math.floor) + Object.groupBy([6.1, 4.2, 6.3], Math.floor) - _.groupBy(['one', 'two', 'three'], 'length'); + Object.groupBy(['one', 'two', 'three'], word => word.length)
Как видно, функции не полностью идентичны. Однако, если в вашей кодовой базе активно используется метод из Lodash, стоит задуматься о замене. Особенно это важно для фронтенда, так как отказ от Lodash уменьшит размер бандла.
Метод group
поддерживается всеми основными браузерами, начиная с марта 2024 года. Если требуется поддержка более старых браузеров, это не проблема — написать полифил довольно легко:
if (!('groupBy' in Object)) { Object.groupBy = (items, getKey) => Array.from(items).reduce((result, item, index) => { const key = getKey(item, index) result[key] ??= [] result[key].push(item) return result }, {})}if (!('groupBy' in Map)) { Map.groupBy = (items, getKey) => Array.from(items).reduce((result, item, index) => { const key = getKey(item, index) if (!result.has(key)) result.set(key, []) result.get(key).push(item) return result }, new Map())}
if (!('groupBy' in Object)) { Object.groupBy = (items, getKey) => Array.from(items).reduce((result, item, index) => { const key = getKey(item, index) result[key] ??= [] result[key].push(item) return result }, {}) } if (!('groupBy' in Map)) { Map.groupBy = (items, getKey) => Array.from(items).reduce((result, item, index) => { const key = getKey(item, index) if (!result.has(key)) result.set(key, []) result.get(key).push(item) return result }, new Map()) }
Если вы используете Typescript в своём проекте, убедитесь, что у вас версия 5.4 или новее. Начиная с неё в стандартных библиотеках есть типизация Object
и Map
. Подключить типизацию можно добавлением в tsconfig
библиотек ES
и ES
(для Object
и Map
соответственно):
"compilerOptions": {- "lib": ["DOM", "ES2020"],+ "lib": ["DOM", "ES2020", "ESNext.Object", "ESNext.Collection"], }
"compilerOptions": { - "lib": ["DOM", "ES2020"], + "lib": ["DOM", "ES2020", "ESNext.Object", "ESNext.Collection"], }