Map과 WeakMap의 차이점이 궁금해져서 찾아보았습니다.
0. 공통점
- 둘 다 객체(Object) 처럼 key-value 쌍으로 데이터를 저장합니다.
- 둘 다 임의의 값을 key로 사용할 수 있음 (단, WeakMap은 예외 존재 → 아래 설명).
- 둘 다 get, set, delete, has 메서드를 제공합니다.
1. Map의 특징
Map은 ES6에서 추가된 자료구조로, 기존 객체(Object)의 한계를 보완하기 위해 만들어졌습니다.
객체는 키로 문자열이나 심볼만 사용할 수 있지만, Map은 모든 값을 키로 사용할 수 있습니다.
즉, 객체, 함수, 숫자, 문자열 등 어떤 타입이든 키로 활용할 수 있습니다.
const map = new Map();
const objKey = { id: 1 };
map.set(objKey, 'User');
map.set('role', 'Admin');
console.log(map.get(objKey)); // 'User'
console.log(map.get('role')); // 'Admin'주요 특징
- 키로 모든 자료형을 사용할 수 있습니다.
- 삽입 순서를 유지하며, 순회가 가능합니다.
map.size로 크기를 확인할 수 있습니다.- 내부적으로 강한 참조(strong reference) 를 유지합니다.
내부 동작
Map은 해시 테이블 기반으로 동작하며, 평균 접근 복잡도는 O(1)입니다.
엔진은 키에 대한 강한 참조를 유지하기 때문에, 키로 사용된 객체가 외부에서 제거되어도 Map 내부에는 남아 있습니다.
let obj = { id: 1 };
const map = new Map();
map.set(obj, 'data');
obj = null;
console.log(map.size); // 1이 경우 객체는 외부에서 더 이상 참조되지 않지만, Map이 참조를 유지하고 있으므로 가비지 컬렉션(GC)의 대상이 되지 않습니다.
따라서 대규모 데이터나 동적으로 변하는 객체를 다룰 때는 명시적으로 삭제(delete) 해야 메모리 누수를 방지할 수 있습니다.
2. WeakMap의 개념과 특징
WeakMap은 이름처럼 “약한 참조(weak reference)”를 사용하는 자료구조입니다.
즉, 키로 사용된 객체가 외부에서 더 이상 참조되지 않으면, GC가 해당 객체를 자동으로 해제할 수 있습니다.
이는 메모리 안전성을 높여 주며, 임시 데이터 저장이나 캐시 구조에서 자주 사용됩니다.
let obj = { id: 1 };
const weakMap = new WeakMap();
weakMap.set(obj, 'User');
obj = null; // 외부 참조 제거
// 이후 GC가 발생하면 자동으로 해제됩니다.주요 특징
- 키는 반드시 객체(Object) 여야 합니다.
- 순회(
forEach,for...of)가 불가능합니다. size속성이 없습니다.- 약한 참조를 사용하기 때문에 GC가 자유롭게 객체를 해제할 수 있습니다.
내부 동작
WeakMap은 객체를 WeakRef 형태로 저장합니다.
GC는 객체가 외부에서 더 이상 참조되지 않는다고 판단하면, WeakMap 내부의 데이터도 함께 제거합니다.
이 과정은 비동기적으로 진행되며, 개발자가 명시적으로 감지할 수 없습니다.
이 때문에 WeakMap은 순회나 크기 확인 기능을 지원하지 않습니다.
GC 타이밍에 따라 데이터가 갑자기 사라질 수 있기 때문입니다.
3. Map과 WeakMap 비교
| 구분 | Map | WeakMap |
|---|---|---|
| 키 타입 | 모든 값 (객체, 문자열, 숫자 등) | 객체만 가능 |
| 참조 방식 | 강한 참조 | 약한 참조 |
| GC 관여 | 자동 해제 안 됨 | 외부 참조 없으면 자동 해제 |
| 순회 가능 여부 | 가능 (for...of, forEach) |
불가능 |
| size 속성 | 있음 | 없음 |
| 사용 목적 | 일반 데이터 저장 | 객체 기반 임시 데이터, 캐시, private 데이터 |
Map은 명시적인 데이터 관리가 필요한 경우에 적합하며,
WeakMap은 객체의 생명주기와 데이터의 수명을 일치시킬 때 적합합니다.
4. 사용 시점과 예시
Map을 사용하는 경우
- 명확하게 관리되는 데이터가 필요할 때
- 원시값을 키로 사용할 때
- 순회, 크기 확인, 로깅 등이 필요한 경우
const routeMap = new Map([
['/home', 'HomePage'],
['/login', 'LoginPage'],
]);
for (const [path, page] of routeMap) {
console.log(`${path} -> ${page}`);
}이 경우 Map은 일반적인 키-값 매핑 구조로 동작하며,
순회가 가능하고 데이터 크기를 쉽게 확인할 수 있습니다.
WeakMap을 사용하는 경우
- 객체의 생명주기와 함께 데이터가 사라져야 할 때
- 비공개(private) 데이터를 저장할 때
- 메모리 누수를 방지해야 할 때
const cache = new WeakMap();
function getUserData(user) {
if (!cache.has(user)) {
cache.set(user, fetchFromDB(user.id));
}
return cache.get(user);
}위 예제에서 user 객체가 메모리에서 사라지면,
WeakMap 내부의 캐시 데이터도 자동으로 제거됩니다.
이는 서버 캐시나 프론트엔드 DOM 관리에 매우 유용한 패턴입니다.
5. 성능 및 메모리 관점
Map은 조회, 삽입, 삭제 모두 평균 O(1) 성능을 가집니다.데이터가 쌓이면 누수가 발생할 수 있습니다.- 하지만 메모리 해제는 수동으로 처리해야 합니다.
WeakMap은 성능은 비슷하지만, GC 의존적입니다.- 개발자가 직접 관리할 필요는 없지만, 데이터 개수를 정확히 알 수 없고 순회가 불가능합니다.
정리하자면 Map은 데이터 중심의 구조이고,
WeakMap은 객체 생명주기 중심의 구조입니다.
6. 실무에서의 선택 기준
실무에서는 다음과 같이 구분하는 것이 일반적입니다.
- React, Vue 등 프론트엔드 프레임워크 내부에서는객체가 사라지면 데이터도 함께 정리되므로 메모리 누수를 방지할 수 있습니다.
- DOM 노드나 컴포넌트 상태를 관리할 때
WeakMap을 사용합니다. - Node.js 백엔드 환경에서는캐시나 미들웨어 컨텍스트처럼 요청마다 객체가 달라지는 경우에만
WeakMap을 사용합니다. - 설정값, 사용자 세션, 라우팅 테이블 등 명확히 관리되는 데이터에는
Map을 사용합니다.
// Express 요청별 캐시 예시
const requestCache = new WeakMap();
function middleware(req, res, next) {
if (!requestCache.has(req)) {
requestCache.set(req, new Map());
}
next();
}요청이 종료되면 req 객체가 GC 대상이 되고,
함께 저장된 데이터도 자연스럽게 정리됩니다.
7. 결론
Map과 WeakMap의 가장 큰 차이는 참조 강도와 메모리 관리 방식입니다.
Map은 명시적 관리가 필요한 데이터 구조이며,
WeakMap은 객체의 생명주기에 따라 자동으로 정리되는 구조입니다.
즉,
- 데이터의 수명을 직접 관리해야 한다면 → Map
- 객체의 생명주기와 함께 자동 정리를 원한다면 → WeakMap
이 원칙만 기억해도 대부분의 상황에서 올바른 선택을 할 수 있습니다.
핵심 요약
| 항목 | Map | WeakMap |
|---|---|---|
| 키 | 모든 값 | 객체만 |
| 참조 | 강한 참조 | 약한 참조 |
| GC 해제 | 수동 | 자동 |
| 순회/크기 | 가능 | 불가 |
| 주 용도 | 일반 데이터 저장 | 캐시, private 데이터 |
| 메모리 관리 | 직접 관리 | 자동 관리 |
Map은 구조적이고 예측 가능한 데이터 저장소이며,
WeakMap은 객체 중심의 메모리 친화적 저장소입니다.
두 자료구조의 핵심은 단순한 문법 차이가 아니라,
“데이터 생명주기를 어디서 제어할 것인가”에 있습니다.
'언어(JS,TS) > JavaScript' 카테고리의 다른 글
| javascript [ 백엔드 프레임워크: Nest.js vs Express.js] (0) | 2024.11.19 |
|---|---|
| JS [study: 싱글스레드가 서버를 돌릴수 있는 이유 (nginx를 사용하는 이유) (0) | 2024.11.10 |
| JS [test: forEach VS map VS for (속도 차이 및 원인 분석)] (0) | 2024.11.04 |
| JavaScript [궁금증 : .forEach, .map and .reduce vs for and for..of (속도나 효율비교)] (0) | 2022.09.21 |
| JavaScript [ ES6 : 이터레이터(iterator)와 제너레이터(generator) ] (0) | 2022.08.30 |