본문으로 건너뛰기
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에 대해서 까지 신경쓰지 않아도 된다.

관련 글

  • #turbopack#nextjs#bundler

    Next.js turbopack에서 싱글톤이 두 개가 됐다: scope hoisting 버그와 순환 import

    Next.js 16 turbopack 프로덕션 빌드에서 모듈 스코프 싱글톤이 런타임에 두 개가 됐다. 같은 동기 구간에서 조건 판정이 뒤집히고, 응답이 도착해도 타임아웃이 나는 증상을 번들 산출물로 추적한 기록. scope hoisting의 부분 병합, 순환 import, 이미 고쳐져 있던 upstream 버그, 그리고 뒤늦게 돌린 단일 변수 실험까지.

    2026-08-19·28분
  • #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분

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

RSS 구독 →

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

← Back to the blogIssue on GitHub →