반응형
안녕하세요 😊
오늘은 ES6에서 도입된 컬렉션 객체 **Map**과 **Set**을 정리해보겠습니다.
Map은 키-값 저장소, Set은 중복 없는 값 집합으로, 기존 Object와 Array의 한계를 보완합니다.
실무 예제와 함께 “언제 어떤 걸 써야 하는지”까지 알아보겠습니다.
1) Map 한눈에 보기 – “모든 타입을 키로 쓰는 해시 맵”
특징
- 키에 어떤 타입이든 사용 가능(객체, 함수, NaN 포함)
- 삽입 순서 보장
- 크기: map.size
- 반복: for...of, map.forEach()
// 생성 & 기본 메서드
const m = new Map();
m.set('name', 'Kim');
m.set({ id: 1 }, 'object-key');
m.set(NaN, 'not-a-number');
console.log(m.get('name')); // 'Kim'
console.log(m.has(NaN)); // true
m.delete('name');
console.log(m.size); // 2
Object와 무엇이 다른가요?
- Object는 문자열/심볼만 키로 안정적 사용 → 객체를 키로 쓰기 번거로움
- 키 개수는 직접 세야 함 → Map은 size 제공
- 빈번한 추가/삭제·검색에선 Map이 일반적으로 더 직관적이고 성능 이점
자주 쓰는 패턴
- 빈도 계산(워드 카운트), 캐시(메모이제이션), 그래프 인접 리스트 등
// 빈도 계산
const words = ['a','b','a','c','b','a'];
const freq = new Map();
for (const w of words) {
freq.set(w, (freq.get(w) || 0) + 1);
}
// [['a',3], ['b',2], ['c',1]]
2) Set 한눈에 보기 – “중복 없는 값들의 집합”
특징
- 값의 중복 자동 제거
- 삽입 순서 보장
- 크기: set.size
- 반복: for...of, set.forEach()
const s = new Set([1,2,2,3]);
console.log([...s]); // [1,2,3]
s.add(4);
console.log(s.has(2)); // true
s.delete(1);
s.clear();
Array와 무엇이 다른가요?
- 배열에서 중복 제거하려면 filter/indexOf가 필요 → Set이 더 간단·빠름
실무 패턴
- 중복 제거
const unique = [...new Set(['a','a','b','c','b'])]; // ['a','b','c']
- 교집합 / 차집합 / 합집합
const A = new Set([1,2,3]);
const B = new Set([2,3,4]);
const union = new Set([...A, ...B]); // {1,2,3,4}
const intersection = new Set([...A].filter(x => B.has(x))); // {2,3}
const difference = new Set([...A].filter(x => !B.has(x))); // {1}
3) 순회와 변환 – Map/Set ↔ Array/Object
// Map ↔ Array
const map = new Map([['name','Lee'], ['age',28]]);
const arr = [...map]; // [['name','Lee'], ['age',28]]
// Set ↔ Array
const set = new Set([1,2,3]);
const arr2 = [...set]; // [1,2,3]
// Object → Map
const obj = { a: 1, b: 2 };
const m2 = new Map(Object.entries(obj));
// Map → Object (키가 문자열일 때만 안전)
const obj2 = Object.fromEntries(m2);
4) 성능과 복잡도 감각치
- Map: 평균적으로 get/set/has/delete 모두 O(1) 기대
- Set: add/has/delete O(1) 기대
- Array 중복 체크(includes)는 O(n) → Set 선호
- 크고 빈번한 조회/추가/삭제 로직이면 Map/Set이 유리
5) WeakMap / WeakSet – 메모리 친화적 참조
- 키/값으로 오직 객체 참조만 허용 (원시값 불가)
- 가비지 컬렉션 대상에서 자동 해제(참조가 끊기면 메모리 회수)
- 반복·size 없음(관찰 불가 구조)
const wm = new WeakMap();
let objKey = { id: 1 };
wm.set(objKey, 'private-data');
// objKey = null 로 참조 끊기면, 해당 엔트리 GC 대상
✅ 사용처: 컴포넌트 인스턴스 → 메타데이터, DOM 노드 → 상태 맵핑 등
6) 실무 시나리오 모음
A. 중복 없는 태그 목록 만들기 (Set)
const posts = [
{ tags: ['js','web'] },
{ tags: ['web','react'] },
{ tags: ['css','js'] }
];
const tags = new Set(posts.flatMap(p => p.tags));
console.log([...tags]); // ['js','web','react','css']
B. 객체 키로 상태 저장하기 (Map)
const stateByUser = new Map();
const user1 = { id: 1 }, user2 = { id: 2 };
stateByUser.set(user1, { online: true });
stateByUser.set(user2, { online: false });
console.log(stateByUser.get(user1).online); // true
C. LRU 캐시 느낌의 최근 본 항목(중복 제거 + 최신 순서) (Set)
const recent = new Set();
function see(item) {
if (recent.has(item)) recent.delete(item); // 위치 갱신
recent.add(item);
if (recent.size > 5) recent.delete(recent.values().next().value); // 가장 오래된 항목 제거
}
['a','b','c','a','d','e','f'].forEach(see);
console.log([...recent]); // 최근 본 5개 유지
7) 자주 하는 실수 & 주의점
- Map은 JSON 직렬화가 바로 안 됨 → Object.fromEntries(map) 등으로 변환 후 저장
- Set은 값의 동일성 비교가 === 기준 (객체 레퍼런스가 다르면 다른 값)
- Object에 비해 Map은 직접 프로퍼티 접근(obj.key) 불가 → 반드시 get/set 사용
- 열거 순서 필요 & 키가 비원시값이면 Map 우선,
단순 키-값(문자열 키) + 직렬화가 중요하면 Object 고려
✅ 마무리
- Map: “모든 타입 키 + 빠른 조회/수정/삭제 + 순서 보장”이 필요할 때
- Set: “중복 제거, 집합 연산, 빠른 포함 검사”가 필요할 때
이 둘을 익숙하게 쓰시면, 로직이 깔끔해지고 성능도 안정적으로 개선됩니다.
실무에서 배열·객체만 고집하지 말고, 상황에 맞춰 Map/Set을 선택해 보세요! 😊
반응형
'JavaScript, jQuery' 카테고리의 다른 글
Debounce와 Throttle – 이벤트 최적화 핵심 개념 정리 (0) | 2025.09.14 |
---|---|
Intl 완전 정복 – Date/Number/RelativeTime 현지화 포맷 가이드 (0) | 2025.09.05 |
localStorage & sessionStorage – 브라우저 데이터 저장 완벽 가이드 (1) | 2025.08.31 |
JavaScript fetch() API – 비동기 데이터 가져오기 완벽 가이드 (0) | 2025.08.29 |
JavaScript Date 객체 완전 정복 – 날짜·시간 처리부터 포맷 변환까지 (1) | 2025.08.24 |