본문으로 건너뛰기
yceffort
PostsSeriesTagsAbout🧪 Research
EN

Tweaks

theme
accent palette
film grain
minimal mode
BACK TO INDEX
◆ ESSAY
--min
--year
KOoriginal

mailMail icongithubtwitter
yceffort
•
© 2026
•
https://yceffort.kr
BACK TO INDEX
◆ ESSAY

Javascript Set 그리고 Map

avatar
yceffort
2019-07-18 · 6분
6min
2019year
KOoriginal
javascript

근데 사실.. 컬렉션 필요없지 않을까

자바스크립트에서 일반적인 Object는 key-value쌍을 끊임 없이 추가할 수 있는 형태로 구성되어 있다. 그래서 사실 컬렉션이 필요하지 않은 것 처럼 보일 수도 있다. 그러나 이따금씩 object로 부족할 때가 있다.

  • key 충돌 위험이 존재하는 경우
  • 문자열/심볼 이외의 키 값이 필요한 경우
  • 객체에 얼마나 많은 속성이 있는지 알아낼 수 있는 효과적인 방법이 필요한 경우
  • 객체가 iterable하지 않음. 따라서 for..of 나 ...를 사용할 수 없음

es6에 추가된 컬렉션들은 따라서 멤버 데이터를 드러내기 위해 property를 사용하지 않는다. (obj.key, obj[key] 불가능.) 그리고 이들에는 자유롭게 메소드를 추가할 수 있다.

Set

Set은 value로 이루어진 컬렉션이다. 그리고 수정가능하다. 배열과 같을 것 같지만, 다르다.

let faces = new Set('😀 😁 😂 🤣 😃 😄 😅')
faces.size // 8
faces.add('😂')
  • 일단 (당연하게도) Set에는 같은 value가 중복으로 포함될 수 없다. 기존에 있는걸 추가해도 아무런 변화가 없다.
  • Set은 어떤데이터가 자신의 멤버인지 빠르게 확인하기 위한 목적으로 사용한다
  • 그러나 Set은 index로 값을 조회할 수는 없다.

set 으로 할 수 있는 것

  • new Set(): 비어있는 set 생성

  • set.size: set 데이터 개수 조회

  • set.has(value): value가 set에 존재하는지 조회

  • set.add(value)

  • set.delete(value)

  • sets[Symbol.iterator](): set 안의 값을 순회할 수 있는 새로운 이터레이러를 리턴한다. set을 iterable하게 만들어 준다.

    let faces = new Set('😀 😁 😂 🤣 😃 😄 😅')
    iteratorFaces = faces[Symbol.iterator]()
    for (let i of iteratorFaces) {
      console.log(i)
    }
    
    • set.forEach(f)
    • set.clear
    • set.keys()
    • set.values()
    • set.entries()

Map

Map은 잘 알려진 것처럼, key-value pair로 이루어진 컬렉션이다.

Map으로 할 수 있는 것

  • new Map
  • new Map(pairs)
  • map.has(key)
  • map.size
  • mag.get(key)
  • map.set(key, value)
  • map.delete(key)
  • map.clear()
  • map[Symbol.iterator]() === map.entries()
  • map.forEach(f)
  • map.keys()
  • map.values()

javascript 가 다른점

아래의 코드를 보자.

let messi = new Set()

const 리오넬메시 = {name: '리오넬메시'}
const 라이오넬멧시 = {name: '리오넬메시'}
messi.add(리오넬메시)
messi.add(라이오넬멧시)

console.log(messi.size) //2 ????

리오넬메시와 라이오넬멧시는 내부의 값이 같아 보이기 때문에, set에 한개의 값만 추가 될 것 같지만 사실은 그렇지 않다. 자바스크립트에서는 두개의 값을 다르게 본다. 이유는 자바스크립트가 값을 비교할 때 두가지 다른 방법을 사용하기 때문이다.

  • string, number같은 primitive는 값을 비교한다
  • array, date, object 등은 reference를 비교한다. (메모리의 같은 위치를 참조하고 있는가?)
const 리오넬메시 = {name: '리오넬메시'}
const 라이오넬멧시 = {name: '리오넬메시'}
const 메석대 = 리오넬메시

메석대 === 리오넬메시 // true
메석대 == 라이오넬멧시 // false
리오넬메시 === 라이오넬멧시 //false

본질적으로 같은 메모리를 참조하는 값 끼리만 true를 반환하는 것을 볼 수 있다. (두 object를 비교하는 방법은 여기를 참조)

다시 Set으로 돌아와서, javascript는 저 두 값을 제대로 비교하지 못하기 때문에 set에 두개의 값이 들어가게 된다. 물론 해시코드를 사용하면 가능하지만, javascipt에는 그런거 없다

또 하나 다른 점이라고 한다면, map과 set에 추가한 순서가 곧 순회하는 순서와 같다는 것이다. 이 역시 다른 언어들과는 다른 점이다.

WeakMap, WeakSet

  • WeakMap은 new .has() .get() .set() .delete() 만 지원한다
  • WeakSet은 new .has() .add() .delete() 만 지원한다.
  • WeakSet과 WeakMap의 key는 반드시 object여야 한다.

그렇다. 열거형이 존재하지 않는다. 그 이유는 참조하고 있는 오브젝트가 사라지면 해당 key, value가 사라지는 WeakMap, WeakSet의 특징 때문이다.

let john = {name: 'John'}
// 객체에 접근 가능, 해당 객체는 메모리에서 참조되고 있음.
// 참조를 null로 overwrite
john = null
// 객체는 메모리에서 이제 삭제됨
let john = {name: 'John'}
let array = [john]
john = null // 참조를 null로 overwrite

// john은 객체안에 살아 있기 때문에 가비지 컬렉팅이 되지 않음.
// 그래서 array[0]으로 접근 가능
array[0]
// { name: "John" }

이는 기존 Map, Set에서도 동일하다.

let john = {name: 'John'}

let map = new Map()
map.set(john, '윅')

john = null // 참조를 null로 overwrite

// john은 맵안에서 살아있기 때문에
// map.keys() 로 접근 가능

그러나 WeakMap, WeakSet은 다르다

let john = {name: 'John'}

let weakMap = new WeakMap()
weakMap.set(john, '윅')

john = null // 참조를 null로 overwrite

// john은 메모리에서 사라짐 (가비지 콜렉팅 당함)

그럼 도대체 이것은 언제 쓸까? 객체가 사라지면 자동으로 가비지 콜렉팅 해준다는 특성을 활용해, 아래와 같은 것이 가능하다.

let john = {name: 'John'}
// map: 유저 => 방문횟수
let visitsCountMap = new Map()
visitsCountMap.set(john, 123)

// john이 사라짐
john = null

// 그러나 Map에서는 계속 남아 있으므로, 따로 처리를 해주어야 함.
// 또한 john은 map에서 key로 사용하고 있으므로 메모리에서도 존재함.
console.log(visitsCountMap.size) // 1

그러나 여기서 WeakMap을 사용하면, 자동으로 가비지 콜렉팅이 되므로 Map에 남아있는 key에 대해서 까지 신경쓰지 않아도 된다.

관련 글

  • #javascript#animation#web-animations-api

    number-flow를 구형 브라우저로 이식하기: 다섯 가지 결정과 두 가지 번복

    number-flow가 애니메이션을 켜는 최소 버전은 Chrome 125, Safari 17.2다. 이 하한을 Chrome 66과 WebKit 16.4까지 내리는 포크를 만들면서 내린 결정들과, 뒤집게 된 판단 두 가지, 그리고 자동 강등을 포기한 Safari 버그 조사의 기록.

    2026-08-11·44분
  • #nodejs#security#javascript

    Node.js vm 모듈의 함정: 샌드박스가 아닌 이유

    집필 중인 Node.js Deep Dive의 5.2장(vm 모듈의 함정) 일부를 미리 공개합니다.

    2026-02-27·25분
  • #nodejs#javascript

    Node.js Deep Dive (가제) 베타 리더를 모십니다.

    많관부22

    2026-02-19·5분
  • #javascript#frontend#web-performance

    IntersectionObserver 싱글톤 패턴과 WeakMap으로 메모리 누수 방지하기

    수백 개의 요소를 효율적으로 관찰하면서 메모리 누수도 방지하는 방법

    2026-01-17·20분

새 글을 놓치고 싶지 않으시다면 RSS로 구독해 주세요.

RSS 구독 →

yceffort — 프론트엔드 엔지니어입니다. 발표·기술 자문·기고 문의는 이곳에서 받고 있습니다.

← Back to the blogIssue on GitHub →