MapSet은 ES6에서 추가된 컬렉션 자료구조입니다. 일반 객체와 배열로도 비슷한 일을 할 수 있지만, 특정 상황에서는 Map과 Set이 훨씬 적합합니다.

Map — 키-값 저장소

Map은 어떤 타입이든 키로 사용 할 수 있는 키-값 저장소입니다.

JS
const map = new Map();

// 다양한 타입의 키
map.set("name", "정훈");
map.set(42, "숫자 키");
map.set(true, "불린 키");

const objKey = { id: 1 };
map.set(objKey, "객체 키"); // 객체도 키로 사용 가능!

console.log(map.get("name"));  // "정훈"
console.log(map.get(42));      // "숫자 키"
console.log(map.get(objKey));  // "객체 키"
console.log(map.size);         // 4

Map vs Object

JS
// 1. 키 타입 — Object는 문자열/Symbol만 가능
const obj = {};
obj[1] = "a";
obj["1"] = "b";
console.log(obj[1]); // "b" — 1이 "1"로 변환되어 덮어씀

const map = new Map();
map.set(1, "a");
map.set("1", "b");
console.log(map.get(1));   // "a" — 구분됨!
console.log(map.get("1")); // "b"

// 2. 순서 보장 — Map은 삽입 순서 보장
// Object도 ES2015+ 스펙에서는 대부분 순서 보장하지만, 정수 키는 오름차순 정렬됨

// 3. size — Map은 O(1), Object는 Object.keys().length
console.log(map.size); // 간단!

// 4. 이터러블 — Map은 직접 순회 가능
for (const [key, value] of map) {
  console.log(key, value);
}

Map의 주요 메서드

JS
const map = new Map([
  ["a", 1],
  ["b", 2],
  ["c", 3],
]);

map.has("a");    // true — 존재 확인
map.delete("b"); // true — 삭제
map.clear();     // 전체 삭제

// 순회 메서드
map.keys();    // MapIterator {"a", "c"}
map.values();  // MapIterator {1, 3}
map.entries(); // MapIterator {["a", 1], ["c", 3]}
map.forEach((value, key) => console.log(key, value));

Map을 쓰면 좋은 경우

JS
// 1. 빈번한 추가/삭제 — Object보다 성능 우수
const cache = new Map();
cache.set(url, response);
cache.delete(oldUrl);

// 2. DOM 요소를 키로 사용
const elementData = new Map();
elementData.set(document.body, { scrollY: 0 });

// 3. 객체 → Map → 객체 변환
const obj = { a: 1, b: 2 };
const map = new Map(Object.entries(obj));
const backToObj = Object.fromEntries(map);

Set — 중복 없는 값 컬렉션

Set은 고유한 값 만 저장하는 컬렉션입니다.

JS
const set = new Set();

set.add(1);
set.add(2);
set.add(2); // 무시됨 — 이미 존재
set.add(3);

console.log(set.size); // 3
console.log(set.has(2)); // true

set.delete(2);
console.log(set.has(2)); // false

배열 중복 제거 — 가장 흔한 활용

JS
const arr = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(arr)];
console.log(unique); // [1, 2, 3, 4]

// 문자열 중복 제거
const chars = [...new Set("banana")].join("");
console.log(chars); // "ban"

이 패턴은 코딩 테스트에서 정말 자주 쓰입니다.

Set의 참조 비교

JS
const set = new Set();

set.add({ name: "a" });
set.add({ name: "a" }); // 서로 다른 객체이므로 둘 다 추가됨

console.log(set.size); // 2 — 참조가 다르면 다른 값으로 취급

집합 연산 (ES2025)

JS
const a = new Set([1, 2, 3, 4]);
const b = new Set([3, 4, 5, 6]);

// ES2025 Set 메서드
a.union(b);               // Set {1, 2, 3, 4, 5, 6} — 합집합
a.intersection(b);         // Set {3, 4} — 교집합
a.difference(b);           // Set {1, 2} — 차집합
a.symmetricDifference(b);  // Set {1, 2, 5, 6} — 대칭차집합
a.isSubsetOf(b);           // false — 부분집합 여부
a.isSupersetOf(b);         // false — 상위집합 여부
a.isDisjointFrom(b);       // false — 교집합 없는지 여부

// ES2025 이전 방식 (폴리필)
const union = new Set([...a, ...b]);
const intersection = new Set([...a].filter((x) => b.has(x)));
const difference = new Set([...a].filter((x) => !b.has(x)));

WeakMap과 WeakSet

키(WeakMap) 또는 값(WeakSet)에 객체만 저장할 수 있고, 가비지 컬렉션을 방해하지 않습니다.

JS
const weakMap = new WeakMap();

let obj = { data: "important" };
weakMap.set(obj, "메타데이터");

console.log(weakMap.get(obj)); // "메타데이터"

obj = null; // 원래 객체에 대한 참조가 사라지면
// weakMap에서도 자동으로 제거됨 (GC에 의해)

WeakMap의 활용

JS
// 1. 프라이빗 데이터 저장
const privateData = new WeakMap();

class User {
  constructor(name, password) {
    this.name = name;
    privateData.set(this, { password }); // 외부에서 접근 불가
  }

  checkPassword(input) {
    return privateData.get(this).password === input;
  }
}

// 2. DOM 요소에 데이터 연결 (메모리 누수 방지)
const elementMeta = new WeakMap();
function trackElement(el) {
  elementMeta.set(el, { clicks: 0 });
}
// el이 DOM에서 제거되면 WeakMap에서도 자동 정리

언제 뭘 쓸까?

상황추천 자료구조
일반 키-값 저장 (문자열 키)Object
비문자열 키, 빈번한 추가/삭제Map
중복 제거, 존재 여부 확인Set
메모리 누수 방지 (캐시, DOM)WeakMap / WeakSet
JSON 직렬화 필요Object (Map은 직렬화 안 됨)

** 기억하기 **: Object는 "구조화된 데이터", Map은 "딕셔너리", Set은 "중복 없는 목록"으로 기억하면 됩니다. 특히 [...new Set(arr)]로 배열 중복 제거하는 패턴은 코딩 테스트 필수입니다.

댓글 로딩 중...