Object.groupBy() — 배열 그룹화
ES2024 Object.groupBy()와 Map.groupBy()로 배열을 키 기준으로 분류하는 방법, reduce를 사용하던 기존 방식과의 비교, 실전 패턴을 정리합니다.
지난 글에서 structuredClone()을 살펴봤습니다. 이번에는 ES2024에 추가된 **Object.groupBy()**와 **Map.groupBy()**를 다룹니다. 배열을 특정 기준으로 분류하는 작업을 위해 매번 reduce()를 직접 구현하던 번거로움을 해결하는 내장 메서드입니다.
배열 그룹화란?
배열 요소를 어떤 기준(카테고리, 상태, 범위 등)에 따라 분류해 각 그룹별 배열로 묶는 작업입니다.
// 기존 방식 — reduce로 직접 구현
const grouped = items.reduce((acc, item) => {
const key = item.status;
(acc[key] ??= []).push(item);
return acc;
}, {});
매번 이 패턴을 반복하는 대신, Object.groupBy()가 같은 작업을 선언적으로 처리합니다.
Object.groupBy()
Object.groupBy(iterable, callbackFn) 형식으로 사용합니다. 콜백이 반환하는 문자열 키를 기준으로 요소를 분류하고, null 프로토타입을 가진 객체를 반환합니다.
const products = [
{ name: '노트북', category: '전자제품', price: 1_200_000 },
{ name: '키보드', category: '전자제품', price: 80_000 },
{ name: '책상', category: '가구', price: 350_000 },
{ name: '의자', category: '가구', price: 200_000 },
{ name: '마우스', category: '전자제품', price: 40_000 },
];
const byCategory = Object.groupBy(products, p => p.category);
byCategory['전자제품'];
// [노트북, 키보드, 마우스]
byCategory['가구'];
// [책상, 의자]
Map.groupBy()
키가 문자열이 아닌 임의 타입(객체, 숫자 등)이어야 할 때는 Map.groupBy()를 사용합니다.
const EXPENSIVE = { label: '고가', min: 500_000 };
const MIDRANGE = { label: '중가', min: 100_000 };
const BUDGET = { label: '저가', min: 0 };
const byPriceRange = Map.groupBy(products, p => {
if (p.price >= 500_000) return EXPENSIVE;
if (p.price >= 100_000) return MIDRANGE;
return BUDGET;
});
byPriceRange.get(EXPENSIVE); // [노트북]
byPriceRange.get(MIDRANGE); // [책상]
byPriceRange.get(BUDGET); // [키보드, 의자, 마우스]
null 프로토타입 반환의 의미
Object.groupBy()가 반환하는 객체는 Object.create(null)로 만들어진 null 프로토타입 객체입니다.
const g = Object.groupBy(['a', 'b', 'a'], x => x);
Object.getPrototypeOf(g); // null
// 주의: hasOwnProperty 같은 메서드 없음
g.hasOwnProperty; // undefined
// Object.hasOwn()을 사용해야 함
Object.hasOwn(g, 'a'); // true
다양한 그룹화 기준
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 홀수/짝수
const byParity = Object.groupBy(numbers,
n => n % 2 === 0 ? 'even' : 'odd'
);
// { even: [2,4,6,8,10], odd: [1,3,5,7,9] }
// 범위별
const byRange = Object.groupBy(numbers, n => {
if (n <= 3) return 'low';
if (n <= 7) return 'mid';
return 'high';
});
// { low: [1,2,3], mid: [4,5,6,7], high: [8,9,10] }
이터러블 지원
두 메서드는 배열뿐만 아니라 Set, Map, 제너레이터 등 모든 이터러블을 첫 번째 인자로 받습니다.
const set = new Set(['apple', 'banana', 'avocado', 'blueberry']);
const byFirstLetter = Object.groupBy(set, s => s[0]);
// { a: ['apple', 'avocado'], b: ['banana', 'blueberry'] }
지원 환경
Chrome 117+, Firefox 119+, Safari 17.4+, Node.js 21+에서 지원됩니다. 이전 환경에서는 core-js의 폴리필 또는 Array.prototype.reduce()로 대체할 수 있습니다.
지난 글: structuredClone()
다음 글: 배열 불변 메서드 (toSorted, toReversed, with)
읽어주셔서 감사합니다. 😊