Map은 키와 값을 짝지어 담습니다. set으로 짝을 담고 get으로 키의 값을 꺼냅니다. Set은 같은 값을 한 번만 담아, 겹친 값을 없앨 때 씁니다.
객체로도 키로 값을 찾는 표를 만들 수 있지만, Map은 짝을 다루는 일마다 메서드가 있습니다. 겹친 주문을 빼고 메뉴가 몇 가지 팔렸는지 셀 때는 Set을 씁니다. 이 레슨에서는 Map에서 없는 키를 꺼내면 무엇이 나오는지 그림에서 먼저 맞혀 보고, 겹친 주문이 Set에서 하나로 합쳐지는 것을 봅니다.
1Map에 담고 꺼내기: set과 get
그림 첫 장면의 코드에 찍는 줄 셋을 더했습니다.
const menu = new Map();
menu.set('커피', 4000);
menu.set('라테', 4500);
const p = menu.get('라테');
const q = menu.get('녹차');
console.log(p, q);
console.log(menu.has('녹차'));
console.log(menu.size);
4500 undefined
false
21번 줄의 new Map()은 짝이 하나도 없는 새 Map을 만듭니다. 2번 줄의 menu.set('커피', 4000)은 키 '커피'와 값 4000을 한 짝으로 담고, 3번 줄까지 돌면 짝이 둘이 됩니다.
4번 줄의 menu.get('라테')는 키가 '라테'인 짝을 찾아 값 4500을 돌려줍니다. 5번 줄처럼 없는 키를 꺼내면 멈추지 않고 undefined를 돌려줍니다.
has는 키가 있는지를 true·false로 답하고, size는 짝의 수입니다. size는 배열의 length처럼 괄호 없이 씁니다.
그림에서 2·3번 줄은 Map 칸에 줄을 하나씩 더하고, 4번 줄은 키 '라테'의 값 4500을 꺼내 이름 p를 붙입니다.
2같은 키로 다시 담으면
같은 키 '라테'로 set을 두 번 하면 무엇이 찍힐까요? 두 줄을 먼저 정한 뒤 펼쳐 보세요.
const menu = new Map();
menu.set('라테', 4500);
menu.set('라테', 5000);
console.log(menu.size);
console.log(menu.get('라테'));
실행 결과 보기
1
5000예상과 다르면 그곳이 배울 곳입니다. 3번 줄은 짝을 하나 더 담지 않고, 이미 있는 '라테' 짝의 값만 5000으로 바꿉니다.
Map에서 키는 한 번만 있습니다. 객체에서 이미 있는 키에 값을 담으면 그 줄의 값만 바뀌던 것과 같습니다(객체: 이름 붙은 칸 묶음).
3Set으로 겹친 값 없애기
그림 둘째 장면의 코드에 찍는 줄 셋을 더했습니다.
const orders =
['커피', '라테', '커피'];
const kinds = new Set(orders);
const list = [...kinds];
console.log(kinds);
console.log(kinds.size);
console.log(list);
Set(2) { '커피', '라테' }
2
[ '커피', '라테' ]1~2번 줄은 등호 뒤에서 나눈 한 문장입니다.
3번 줄의 new Set(orders)는 배열의 칸을 앞에서부터 읽어, 처음 보는 값만 새 Set에 담습니다. 셋째 칸 '커피'는 이미 담겨 있어 다시 담지 않습니다. 그래서 칸이 셋인 배열에서 값이 둘인 Set이 생기고, size는 2입니다.
Set은 값을 처음 본 차례대로 담지만 자리 번호는 붙이지 않습니다. 번호로 꺼내려면 4번 줄처럼 펼치기 [...kinds]로 새 배열을 만듭니다(배열 바꾸기와 복사).
그림에서 3번 줄은 orders 배열의 칸 셋을 읽어 값이 둘인 Set을 만들고, 4번 줄은 그 값으로 새 배열을 만듭니다.
예제
오늘 매출과 팔린 메뉴 수
메뉴 가격을 Map에 담고, 오늘 주문을 하나씩 꺼내 가격을 더합니다. 팔린 메뉴가 몇 가지인지는 Set으로 셉니다.
const menu = new Map();
menu.set('커피', 4000);
menu.set('라테', 4500);
menu.set('쿠키', 2000);
const orders =
['커피', '라테', '커피', '쿠키'];
let total = 0;
for (const item of orders) {
const price = menu.get(item);
total = total + price;
}
console.log(`${total}원`);
const kinds = new Set(orders);
console.log(`${kinds.size}가지`);
14500원
3가지9번 줄의 menu.get(item)이 주문한 메뉴 이름을 키로 가격을 찾습니다. 13번 줄의 Set은 두 번 들어온 '커피'를 하나로 합쳐, 주문 넷에서 메뉴 세 가지를 셉니다.
자주 틀리는 곳
틀린 생각: Map에도 객체처럼 대괄호로 짝을 담는다.
객체에는 menu['라테'] = 4500처럼 대괄호로 줄을 더했으니, Map에도 같은 꼴로 짝이 들어갈 것 같습니다.
const menu = new Map();
menu['커피'] = 4000;
console.log(menu.get('커피'));
console.log(menu.size);
undefined
0대괄호는 Map에 짝을 담지 않고, menu에 속성 하나를 더합니다. get과 size는 짝만 보니, 짝이 0개인 Map에서 '커피'를 찾지 못합니다.
맞는 규칙: Map에는 set으로 담고 get으로 꺼냅니다. 대괄호나 점으로 담은 것은 Map의 짝이 아닙니다.
틀린 생각: Set도 배열처럼 0번 자리부터 값을 꺼낼 수 있다.
Set도 값을 담은 차례가 있으니, 배열처럼 번호로 꺼낼 수 있을 것 같습니다.
const kinds =
new Set(['커피', '라테']);
console.log(kinds[0]);
undefinedSet은 차례대로 담지만 자리 번호를 붙이지 않아, kinds[0]이 찾을 0번 자리가 없습니다. 오류 없이 undefined가 나와 틀린 줄을 알아채기 어렵습니다.
맞는 규칙: Set의 값은 번호로 꺼내지 않습니다. 값을 하나씩 다루려면 for (const kind of kinds)처럼 for...of로 돕니다.
틀린 생각: Map을 찍으면 객체처럼 { '라테': 4500 }으로 보인다.
Map도 키와 값을 짝지어 담으니, 찍으면 객체와 같은 꼴로 보일 것 같습니다.
const menu = new Map();
menu.set('라테', 4500);
console.log(menu);
Map(1) { '라테' => 4500 }Map을 찍으면 맨 앞에 종류와 짝의 수 Map(1)이 나오고, 짝은 키 => 값으로 보입니다. 객체의 줄은 '라테': 4500처럼 쌍점(:)으로 보입니다.
맞는 규칙: 찍은 꼴에서 => 기호는 Map의 짝이고 :은 속성입니다. 첫째 코드의 menu를 찍으면 Map(0) { '커피': 4000 }이 나와, 짝은 0개이고 '커피'는 대괄호로 더한 속성이라는 것이 보입니다.
틀린 생각: new Set(orders)는 겹친 값을 뺀 배열을 돌려준다.
겹친 값을 뺀 결과도 배열일 것 같아, 배열처럼 length로 셉니다.
const orders =
['커피', '라테', '커피'];
const kinds = new Set(orders);
console.log(kinds.length);
console.log(kinds.size);
undefined
2new Set이 돌려주는 것은 배열이 아니라 Set입니다. Set에는 length가 없어 undefined가 나오고, 값의 수는 size가 셉니다.
맞는 규칙: 겹친 값을 뺀 배열이 필요하면 [...new Set(orders)]처럼 Set을 펼쳐 새 배열을 만듭니다.
확인 문제
1. 메뉴별 재고를 Map에 적습니다. 무엇이 찍힐까요? 세 줄을 쓰세요.
const stock = new Map();
stock.set('커피', 10);
stock.set('라테', 5);
stock.set('커피', 8);
console.log(stock.get('커피'));
console.log(stock.size);
console.log(stock.has('녹차'));
힌트
4번 줄의 키가 이미 있는지, size가 무엇을 세는지 봅니다.
정답
8
2
false4번 줄은 키 '커피'가 이미 있어 짝을 더하지 않고 값만 8로 바꿉니다. 그래서 '커피'의 값은 8이고 짝은 둘입니다. '녹차'는 담은 적이 없어 has가 false를 답합니다.
흔한 오답은 10과 3입니다. set을 부를 때마다 짝이 하나씩 는다고 본 것입니다. 셋째 줄을 undefined로 쓴 답은 has를 get처럼 본 것이고, has는 늘 true나 false로 답합니다.
2. 오늘 주문에서 겹친 메뉴를 뺀 배열을 찍으려 했는데, 아래 코드는 Set(3) { '라테', '커피', '녹차' }를 찍습니다. 3번 줄만 고쳐 [ '라테', '커피', '녹차' ]가 찍히게 하세요.
const orders =
['라테', '커피', '라테', '녹차'];
const list = new Set(orders);
console.log(list);
힌트
Set에 담긴 값을 꺼내 새 배열의 칸으로 늘어놓는 기호를 떠올립니다.
정답
const list =
[...new Set(orders)];3번 줄을 이 한 문장으로 바꿉니다(등호 뒤에서 나눴습니다). new Set(orders)가 겹친 '라테'를 하나로 합친 Set을 만들고, 대괄호 안의 ... 기호가 그 값을 처음 본 차례대로 펼쳐 새 배열을 만듭니다.
흔한 오답은 ... 기호를 빠뜨린 [new Set(orders)]입니다. Set을 펼치지 않고 통째로 칸 하나에 담아, Set이 든 배열이 찍힙니다. [...orders]는 겹친 '라테'까지 칸 넷을 그대로 옮깁니다.
3. 과목별 점수를 Map에 적습니다. 찍히는 두 줄을 보기에서 고르세요.
const scores = new Map();
scores.set('국어', 90);
scores['수학'] = 80;
console.log(scores.size);
console.log(scores.get('수학'));
- ①
2·80 - ②
1·undefined - ③
1·80
힌트
3번 줄이 Map에 짝을 담는지, get이 무엇에서 찾는지 봅니다.
정답
1
undefined②입니다. 3번 줄의 대괄호는 짝을 담지 않고 scores에 속성을 더합니다. 그래서 짝은 2번 줄의 '국어' 하나뿐이고, get은 짝에서 '수학'을 찾지 못해 undefined를 돌려줍니다.
- ① 대괄호도
set처럼 짝을 담는다고 봤습니다. scores를 찍어 보면 '수학'만 쌍점(:)으로 보입니다. - ③ 짝은 바르게 셌지만,
get이 대괄호로 더한 속성도 찾는다고 봤습니다.get은 짝에서만 찾습니다.
컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요.
예제 코드를 main.js에 저장해 돌린 뒤, 4번 줄을 menu['쿠키'] = 2000;으로 바꿉니다. 두 줄에 무엇이 찍힐지 먼저 적고, 바꿔 돌려서 맞춰 봅니다. 첫 줄이 NaN원이 아니면 '자주 틀리는 곳' 첫째를 다시 봅니다.
저장하고 돌리는 법은 내 컴퓨터에서 돌려 보기에 있습니다.