logo

DowanKim

33. WeakMap, WeakSet

2026년 4월 14일

자바스크립트

일반적인 맵과 셋은 안에 담긴 객체를 '끝까지' 붙잡고 놓아주지 않지만, 이 '약한(Weak)' 친구들은 객체가 쓸모 없어지면 조용히 함께 사라져 줍니다.


🏗️ 1. 위크맵(WeakMap)의 핵심 특징

가장 큰 특징은 **'참조를 유지하지 않는다'**는 점입니다.

  • 객체만 키가 될 수 있음: 원시값(문자열, 숫자 등)은 키로 사용할 수 없습니다.
  • 약한 참조(Weak Reference): 위크맵의 키로 쓰인 객체를 참조하는 곳이 아무것도 없게 되면, 해당 객체는 메모리와 위크맵에서 자동으로 삭제됩니다.
  • 반복 불가능: keys(), values(), size 등을 지원하지 않습니다. (가비지 컬렉션의 시점이 불확실하기 때문에 전체 리스트를 알 수 없습니다.)

🛠️ 주요 메서드

  • weakMap.get(key) / set(key, value)
  • weakMap.has(key) / delete(key)

💡 2. 실무 유스 케이스 (Use Cases)

① 부차적인 데이터 저장 (Metadata)

서드파티 라이브러리에서 가져온 객체에 데이터를 붙여야 하는데, 이 데이터가 객체가 살아있을 때만 유효해야 할 때 사용합니다. 객체가 삭제되면 부가 정보도 자동으로 날아갑니다.

② 캐싱 (Caching)

함수 연산 결과를 객체 키에 매핑하여 저장할 때 유용합니다. 객체가 가비지 컬렉션의 대상이 되면 캐시된 결과도 자동으로 청소되어 메모리를 아낄 수 있습니다.


✨ 3. 위크셋(WeakSet)의 핵심 특징

위크맵과 원리는 동일하며, 객체만 저장하는 셋입니다.

  • 동작: 객체가 도달 불가능해지면 셋 내에서도 자동으로 사라집니다.
  • 용도: 주로 "이 객체가 어떤 그룹에 속해 있는가?" 혹은 "방문한 적이 있는가?" 같은 이진(Yes/No) 상태를 체크할 때 씁니다.

🎙️ 기술 면접 대비 (Interview Questions)

Q1. MapWeakMap의 가비지 컬렉션 동작 차이를 설명해 주세요. (중급)

답변: Map은 객체를 키로 가질 때 해당 객체에 대한 강력한 참조를 유지합니다. 따라서 외부에서 객체 참조를 null로 바꿔도 Map이 살아있는 한 객체는 메모리에 남습니다. 반면 WeakMap약한 참조를 사용하므로, 외부 참조가 모두 사라지면 엔진은 해당 객체와 위크맵 내부의 대응하는 값을 자동으로 메모리에서 제거합니다.

Q2. WeakMap에서 반복 메서드(forEach, keys() 등)를 사용할 수 없는 이유는 무엇인가요? (심화)

답변: 자바스크립트 엔진이 가비지 컬렉션을 수행하는 시점은 예측할 수 없기 때문입니다. 가비지 컬렉터가 이미 돌았는지, 혹은 나중에 돌 것인지에 따라 현재 위크맵에 담긴 요소의 수가 시시각각 변할 수 있습니다. 이러한 불확실성 때문에 전체 요소를 순회하거나 개수를 세는 기능은 기술적으로 제공될 수 없습니다.


📝 과제 솔루션 (Practice Review)

1. '읽음' 상태 메시지 관리 (WeakSet)

메시지 객체를 수정하지 않으면서, 메시지가 시스템에서 사라지면 내 목록에서도 자동으로 사라지게 하려면 **WeakSet**이 정답입니다.

2. 읽은 날짜 저장 (WeakMap)

단순 여부가 아니라 '날짜'라는 추가 정보를 저장해야 하므로 **WeakMap**을 사용하여 {메시지객체: 읽은날짜} 형태로 저장하는 것이 가장 효율적입니다.


💡 기억해야 할 중요한 내용

  1. 메모리 관리의 '치트키'입니다. 수동으로 객체를 지우는 cleanup 로직을 짜기 힘들다면 위크맵/위크셋 도입을 먼저 고려하세요.
  2. 은밀한 동반자: 객체의 생명주기와 운명을 함께해야 하는 부수 데이터를 저장할 때 가장 빛을 발합니다.

가장 핵심적인 이유는 **"언제 지워야 할지 판단할 수 있는 '고유한 주소'가 있느냐 없느냐"**의 차이 때문입니다.

자바스크립트 엔진 입장에서 원시값은 "공기"와 같고, 객체는 "특정한 이름표가 붙은 가방"과 같습니다. 왜 WeakMap이 객체만을 위해 설계되었는지 그 철학적인 배경을 노션 스타일로 정리해 드릴게요.


🏗️ 1. 정체성(Identity)의 유무

원시값: "어디에나 있고, 어디에도 없다"

숫자 5나 문자열 "Hello"는 자바스크립트 엔진 안에서 고유한 주소가 없습니다. * 내가 쓴 5와 옆 팀원이 쓴 5는 논리적으로 똑같은 5입니다.

  • "이 숫자 5를 더 이상 아무도 안 쓰니까 메모리에서 삭제하자!"라고 엔진이 결정할 수 있을까요? 불가능합니다. 프로그램 어딘가에서 누군가 또 5를 쓸 수 있으니까요.

객체: "세상에 단 하나뿐인 주소"

반면 객체는 메모리 어딘가에 **특정한 주소(Reference)**를 가지고 태어납니다.

  • let a = {}; let b = {};라고 하면, 모양은 같아도 ab는 완전히 다른 메모리 주소를 가진 별개의 존재입니다.
  • 엔진은 이 **특정한 주소를 가리키는 손길(참조)**이 모두 끊기는 순간을 정확히 포착할 수 있습니다. "아, 주소 0x123번 가방은 이제 아무도 안 쓰는구나! 버려도 되겠다!"라고 판단할 수 있는 것이죠.

🕵️ 2. 가비지 컬렉터의 '추적' 가능성

WeakMap의 'Weak(약한)'이라는 말은 **"가비지 컬렉터의 작업을 방해하지 않겠다"**는 뜻입니다.

  1. 객체의 생사 확인: 가비지 컬렉터는 객체를 추적하다가 "이 주소는 이제 아무도 안 부르네?" 싶으면 지워버립니다. WeakMap은 이 객체가 지워질 때 슬쩍 같이 사라지는 방식으로 동작합니다.
  2. 원시값의 영생: 원시값은 가비지 컬렉션의 대상이 아닙니다. (변수가 사라지는 거지, 5라는 숫자 자체가 메모리 관리 로직에 의해 파괴되는 게 아닙니다.)
    • 만약 WeakMap에 숫자 5를 키로 넣을 수 있다면, 그 5가 **'더 이상 쓰이지 않는 시점'**을 엔진이 알 방법이 없습니다.

🎯 3. WeakMap의 탄생 목적: "객체에 껌 붙이기"

WeakMap이 만들어진 진짜 이유는 **"객체의 수명에 기생하는 데이터를 저장하기 위해서"**입니다.

  • 상황: 내가 남의 가방(외부 객체)에 몰래 내 이름표(데이터)를 붙여놨습니다.
  • 일반 Map: 내가 이름표를 꽉 잡고 있어서, 주인이 가방을 버리려고 해도 이름표 때문에 가방이 안 버려집니다. (메모리 누수)
  • WeakMap: 나는 이름표를 아주 살짝만 잡고 있습니다. 주인이 가방을 버리면 내 이름표도 같이 쓰레기통으로 들어갑니다. (자동 정리)

🎙️ 기술 면접 대비 (Interview Questions)

Q. "왜 WeakMap의 키로는 원시값을 사용할 수 없나요?" (심화)

답변: "원시값은 **참조(Reference)가 아닌 값(Value)**으로 관리되기 때문입니다. 가비지 컬렉션은 '메모리 주소'에 대한 참조가 끊겼을 때 해당 메모리를 회수하는데, 원시값은 고유한 메모리 주소나 식별성을 가지지 않아 엔진이 그 생명 주기를 추적할 수 없습니다. 따라서 객체의 생명 주기에 따라 데이터를 자동으로 정리하는 WeakMap의 설계 원칙상, 추적이 불가능한 원시값은 키로 적합하지 않습니다."


💡 Tech Lead의 한 줄 인사이트

사실 최근 스펙에서는 **Symbol**도 WeakMap의 키로 쓸 수 있게 되었습니다. 심볼 역시 원시값이지만, Symbol('id')는 객체처럼 유일한 정체성을 가지기 때문이죠. 결국 핵심은 **"지워야 할 타이밍을 엔진이 알 수 있느냐"**에 달려 있습니다.

이제 원시값과 객체의 메모리 관리 차이가 좀 느껴지시나요? 이 개념은 나중에 **클로저(Closure)**나 대규모 상태 관리를 이해할 때 엄청난 밑바탕이 될 거예요. 다음 주제로 넘어가 볼까요, 아니면 이 '참조'의 세계에 대해 더 궁금한 게 있으신가요?

요약

위크맵은 과 유사한 컬렉션입니다. 위크맵을 구성하는 요소의 키는 오직 객체만 가능합니다. 키로 사용된 객체가 메모리에서 삭제되면 이에 대응하는 값 역시 삭제됩니다.

위크셋은 과 유사한 컬렉션입니다. 위크셋엔 객체만 저장할 수 있습니다. 위크셋에 저장된 객체가 도달 불가능한 상태가 되면 해당 객체는 메모리에서 삭제됩니다.

두 자료구조 모두 구성 요소 전체를 대상으로 하는 메서드를 지원하지 않습니다. 구성 요소 하나를 대상으로 하는 메서드만 지원합니다.

객체엔 ‘주요’ 자료를, 위크맵과 위크셋엔 ‘부수적인’ 자료를 저장하는 형태로 위크맵과 위크셋을 활용할 수 있습니다. 객체가 메모리에서 삭제되면, (그리고 오로지 위크맵과 위크셋의 키만 해당 객체를 참조하고 있다면) 위크맵이나 위크셋에 저장된 연관 자료들 역시 메모리에서 자동으로 삭제됩니다.