8단원 '객체'의 아홉 레슨에서 9문제를 내고, 1~7단원에서 3문제를 섞었습니다. 앞 단원 문제가 어느 레슨인지는 정답을 펼치면 보입니다. 출력을 쓰는 문제는 빈칸과 줄바꿈까지 종이에 끝까지 쓴 뒤 정답을 펼치세요. 줄 수를 알려 주지 않는 문제는 마지막 줄까지 다 씁니다. 객체를 다루는 코드는 객체가 몇 개 있는지, 이름표가 어느 객체에 붙는지 적으며 따라가면 덜 틀립니다. 막히면 정답 앞의 힌트를 먼저 펼칩니다. 점수는 매기지 않습니다.
한 번에 다 풀 필요는 없습니다. 문제 1~10은 폰으로도 풀 수 있고(약 30~40분), 끝의 만들어 보기 둘은 컴퓨터에서 Node로 직접 돌려 봅니다. 이 단원을 건너뛰어도 되는지 보려면 문제 1 · 2 · 4 · 6 · 8 · 9 여섯을 먼저 풀어 보세요(약 15분). 건너뛸지 볼 때는 힌트를 펴지 않고 풉니다. 힌트를 펴고 맞힌 문제나 짐작으로 맞힌 문제는 틀린 것으로 치고 그 레슨을 봅니다. 모두 맞으면 이 단원 레슨은 건너뛰되, 이 여섯이 묻지 않는 세 레슨(객체 돌기 · 단축 속성과 나머지 모으기 · JSON: 객체와 글 사이)은 문제 10과 12를 풀어 보고 정합니다. 틀린 문제가 있으면 그 정답 끝의 레슨만 봅니다. 파이썬을 배웠다면 파이썬과 달라지는 큰 곳(배열에 in · 쉼표로 맞바꾸기)이 이 여섯에 들어 있습니다(정답의 '파이썬에서는' 줄). 끝의 만들어 보기 둘은 골라서 풉니다.
끝의 두 문제는 프로그램을 직접 만들어 봅니다. 컴퓨터가 있으면 저장해 돌려 맞춰 보고, 폰으로만 본다면 문제에 적힌 값으로 내 코드를 한 줄씩 따라가 나와야 할 화면과 맞춰 봅니다. 실행 결과는 모두 Node 26으로 돌린 것입니다.
문제 1
샷 수를 담은 배열과 주문 객체에 in으로 물어봅니다. 무엇이 찍힐까요? 세 줄을 글자 그대로 쓰세요.
const shots = [1, 2];
const order = { shot: 2 };
console.log(2 in shots);
console.log(2 in order);
console.log('shot' in order);
힌트
1번 줄 shots의 칸 값과 자리 번호, 2번 줄 order의 키와 값을 먼저 적어 보세요.
힌트 둘
in이 그중 무엇을 묻는지 떠올려 봅니다.
정답
false
false
true- 3번 줄:
in은 왼쪽을 키로 보고 그 키가 있는지 묻습니다. 배열의 키는 자리 번호 0과 1이라, 값 2가 칸에 들어 있어도 자리 번호 2가 없어false입니다. - 4번 줄: order의 키는
shot하나입니다. 값 2가 칸에 들어 있어도 키 2는 없어false입니다. - 5번 줄: 키
'shot'이 있어true입니다.
흔한 오답은 true · true · false나 true · false · true로 쓰는 것입니다. 앞의 것은 in이 값이 있는지 묻는다고 본 것입니다. 뒤의 것은 배열에서는 값을, 객체에서는 키를 묻는다고 보았거나, 칸 수 2를 자리 번호로 보아 자리 번호 2도 있다고 본 것입니다(끝도 든다는 생각). 배열에 값이 있는지는 shots.includes(2)로 물어 true를 얻습니다.
파이썬에서는 2 in [1, 2]가 리스트의 값을 물어 True입니다 — 자바스크립트 in은 배열에서도 키(자리 번호)를 묻고, 값은 includes로 묻습니다.
다시 볼 레슨: 객체: 이름 붙은 칸 묶음
문제 2
주문 객체에 샷을 하나 더하는 함수입니다. 무엇이 찍힐까요? 두 줄을 글자 그대로 쓰세요.
function addShot(order) {
order.shot = order.shot + 1;
return { ...order };
}
const a = { shot: 1 };
const b = addShot(a);
console.log(a.shot, b.shot);
console.log(a === b);
힌트
6번 줄에서 addShot을 부를 때 객체가 몇 개 있는지, 매개변수 order가 어느 객체에 붙는지 그려 보세요. 3번 줄이 지난 뒤에는 객체가 몇 개인지도 세어 봅니다.
정답
2 2
false- 5번 줄: 객체
{ shot: 1 }을 만들고 a가 붙습니다. - 6번 줄: addShot을 부르면 매개변수 order가 a가 가리키는 그 객체에 붙습니다. 객체는 복사되지 않고 이름표만 하나 더 붙습니다.
- 2번 줄: order로 그 객체의 shot 칸을 2로 바꿉니다. a도 같은 객체를 가리키니
a.shot도 2입니다. - 3번 줄:
{ ...order }는 칸을 펼쳐 새 객체{ shot: 2 }를 만들어 돌려주고, b가 그 새 객체에 붙습니다. - 7번 줄:
2 2를 찍습니다. - 8번 줄:
===연산자는 두 이름이 같은 객체를 가리키는지 묻습니다. 칸 값이 같아도 a와 b는 다른 객체라false입니다.
흔한 오답은 첫 줄을 1 2로 쓰거나 둘째 줄을 true로 쓰는 것입니다. 1 2는 인자로 넘길 때 객체가 한 벌 복사되어, 함수 안에서 바꾼 것이 a에 닿지 않는다고 본 것입니다(복사된다는 생각). 6번 줄을 addShot({ ...a })로 써서 사본을 넘겨야 1 2가 찍힙니다. true는 칸 값이 같으면 === 연산자도 참이라고 보았거나, 3번 줄이 order를 그대로 돌려준다고 본 것입니다. 3번 줄이 return order;였다면 b도 같은 객체에 붙어 true가 찍힙니다. == 연산자로 견주어도 다른 객체끼리는 false입니다.
파이썬에서는 a == b가 칸 값을 견주어 True이고, 같은 객체인지는 is로 묻습니다 — 자바스크립트 === 연산자는 객체끼리면 같은 객체인지만 묻습니다.
다시 볼 레슨: 객체를 넘기고 복사하기 · 매개변수와 인자
문제 3
꽃집에서 꽃 이름과 값을 객체 하나로 묶는 함수를 만들었습니다. 이 코드를 실행하면 어떻게 될까요? 알맞은 것을 고르세요.
function make(name, price) {
console.log({ name, price });
}
const rose = make('장미', 3000);
console.log(rose.price);
- ①
{ name: '장미', price: 3000 }과3000을 찍고 끝난다 - ②
{ name: '장미', price: 3000 }을 찍은 뒤 5번 줄에서TypeError로 멈춘다 - ③
{ name: '장미', price: 3000 }과undefined를 찍고 끝난다 - ④ 아무것도 찍지 않고 5번 줄에서
TypeError로 멈춘다
힌트
make 안에 return이 있는지 보고, 4번 줄의 rose가 무엇에 붙는지 적어 보세요.
정답
② — 실행 결과는 이렇습니다.
{ name: '장미', price: 3000 }main.js:5console.log(rose.price); ^ TypeError: Cannot read properties of undefined (reading 'price') at main.js:5:18- 2번 줄:
{ name, price }는{ name: name, price: price }를 줄여 쓴 것입니다. make는 받은 두 값으로 객체를 만들어 찍기만 하고,return이 없습니다. - 4번 줄: make를 부르면 2번 줄이
{ name: '장미', price: 3000 }을 찍습니다.return이 없는 함수는undefined를 돌려주니, rose는undefined에 붙습니다. - 5번 줄:
undefined에는 칸이 없어rose.price를 읽으려다TypeError로 멈춥니다. 객체가 먼저 찍히고 결과에at main.js:5:18줄이 있는 것이 실행 중 오류라는 표시입니다. - ① 2번 줄에서 찍은 객체가 rose에 돌려진다고 본 것입니다(찍는 것과 돌려주는 것이 같다는 생각). 찍은 것은 화면에 보이기만 하고, 부른 쪽이 받는 값은
return이 정합니다. 2번 줄 아래에return { name, price };를 더하면 ①처럼 찍힙니다. - ③ 없는 칸을 읽을 때처럼
undefined가 나온다고 본 것입니다. 객체에 없는 칸을 읽으면undefined이지만,undefined에서 칸을 읽으면TypeError입니다. 5번 줄을rose?.price로 썼다면 ③처럼 찍힙니다. - ④ 실행 중 오류를 문법 오류처럼 본 것입니다. 문법 오류라면 한 줄도 실행되기 전에 멈추지만, 이 코드는 4번 줄까지 실행되어 객체를 찍은 뒤 5번 줄에서 멈춥니다.
다시 볼 레슨: 돌려받은 값 쓰기 · 함수 만들고 부르기 · 단축 속성과 나머지 모으기
문제 4
주문 목록에서 쿠키 주문을 찾아 2개를 더하고, 없는 녹차 주문도 찾아봅니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요. 오류로 멈추면 찍힌 줄 다음에 오류 메시지의 …Error: 줄만 써도 됩니다.
const orders = [
{ item: '라테', qty: 2 },
{ item: '쿠키', qty: 1 },
];
const hit = orders.find(
(o) => o.item === '쿠키',
);
hit.qty = hit.qty + 2;
const miss = orders.find(
(o) => o.item === '녹차',
);
console.log(orders[1].qty);
console.log(miss?.qty ?? 0);
힌트
5~7번 줄의 find가 hit에 주는 것이 orders의 칸 객체 그 자체인지 사본인지 그려 보세요. 9~11번 줄처럼 맞는 칸이 없으면 find가 무엇을 돌려주는지도 봅니다.
정답
모두 두 줄입니다.
3
0- 5~7번 줄:
find는 조건이 참인 첫 칸을 돌려줍니다. 사본을 만들지 않아, hit는 orders의 둘째 칸 객체 그 자체에 붙습니다. - 8번 줄: hit로 그 객체의 qty를 3으로 바꿉니다.
orders[1]도 같은 객체입니다. - 9~11번 줄: item이 '녹차'인 칸이 없어
find는undefined를 돌려주고, miss가undefined에 붙습니다. - 12번 줄:
3을 찍습니다. - 13번 줄: miss가
undefined라miss?.qty는 칸을 읽지 않고undefined를 냅니다.?? 0이 그undefined를 0으로 바꿔0을 찍습니다.
흔한 오답은 첫 줄을 1로 쓰거나, 13번 줄에서 오류로 멈춘다고 쓰는 것입니다. 1은 find가 칸의 사본을 꺼내 준다고 본 것입니다(복사된다는 생각). 오류로 멈춘다고 쓰면 못 찾은 것을 읽으면 바로 오류가 난다고 본 것입니다(없으면 오류라는 생각). find는 못 찾으면 undefined를 돌려줄 뿐이고, ?. 기호로 읽으면 멈추지 않습니다. 13번 줄을 miss.qty ?? 0으로 썼다면 3을 찍은 뒤 13번 줄에서 TypeError로 멈춥니다.
다시 볼 레슨: 객체를 담은 배열 · map·filter·find
문제 5
버스 노선 배열에 정류장을 더합니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요. 오류로 멈추면 찍힌 줄 다음에 오류 메시지의 …Error: 줄만 써도 됩니다.
let stop = '시청';
const route = [stop];
stop = '역전';
route.push(stop);
console.log(route);
console.log(stop);
힌트
2번 줄에서 route의 첫 칸에 들어가는 것이 이름 stop인지, 그때 stop이 붙어 있던 값인지 보세요. 3번 줄이 옮겨 붙이는 것이 무엇인지도 봅니다.
정답
모두 두 줄입니다.
[ '시청', '역전' ]
역전- 1번 줄: stop이 글자 '시청'에 붙습니다.
- 2번 줄: 배열을 만드는 그때 stop이 붙어 있던 값 '시청'을 첫 칸에 담습니다(규칙 2). 칸에 들어가는 것은 이름 stop이 아니라 값입니다.
- 3번 줄: 이름 stop만 '역전'으로 옮겨 붙입니다(규칙 3). route의 첫 칸은 '시청' 그대로입니다.
- 4번 줄: 지금 stop이 붙은 '역전'을 route 끝에 더합니다. route를
const로 만들었어도 배열 안은 바꿀 수 있습니다. - 5~6번 줄:
[ '시청', '역전' ]과역전을 찍습니다.
흔한 오답은 첫 줄을 [ '역전', '역전' ]으로 쓰거나, 4번 줄에서 멈춘다고 쓰는 것입니다. [ '역전', '역전' ]은 첫 칸이 이름 stop을 따라 '역전'으로 바뀐다고 본 것입니다(따라 옮겨 간다는 생각). 4번 줄에서 멈춘다고 쓰면 const로 만든 배열은 바꿀 수 없다고 본 것입니다(const는 얼린다는 생각). const가 막는 것은 route를 다른 값에 다시 붙이는 일뿐입니다. 1번 줄을 const stop으로 만들었다면 3번 줄에서 stop을 다시 붙이려다 TypeError로 멈춥니다.
다시 볼 레슨: 이름표 다시 붙이기와 const · 배열과 이름 둘
문제 6
주문한 음료를 두 객체 a와 b에 셉니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요. 오류로 멈추면 찍힌 줄 다음에 오류 메시지의 …Error: 줄만 써도 됩니다.
const drinks =
['모카', '라테', '모카'];
const a = {};
const b = {};
for (const item of drinks) {
const n = a[item] ?? 0;
a[item] = n + 1;
b[item] = b[item] + 1;
}
console.log(a['모카'], b['모카']);
console.log('라테' in b);
힌트
첫 바퀴의 a['모카']와 b['모카']가 무엇인지부터 적어 보세요.
힌트 둘
없는 칸을 읽으면 무엇이 나오는지, 그 값에 1을 더하면 무엇이 되는지 떠올려 봅니다.
정답
모두 두 줄입니다.
2 NaN
true- 6~7번 줄: 첫 바퀴의
a['모카']는 없는 칸이라undefined이고,?? 0이 0으로 바꿔 n이 0에 붙습니다. a의 '모카' 칸이 1로 생깁니다. 셋째 바퀴에 다시 '모카'를 만나 n이 1, 칸이 2가 됩니다. - 8번 줄: 첫 바퀴의
b['모카']도undefined이고,undefined + 1은NaN입니다. b의 '모카' 칸이NaN으로 생깁니다. 셋째 바퀴의NaN + 1도NaN입니다. 둘째 바퀴에는 '라테' 칸이NaN으로 생깁니다. - 10번 줄:
2 NaN을 찍습니다. - 11번 줄: b에 '라테' 칸이
NaN값으로 생겨 있으니true입니다.
흔한 오답은 첫 줄을 2 2로 쓰거나, 8번 줄에서 오류로 멈춘다고 쓰거나, 둘째 줄을 false로 쓰는 것입니다. 2 2는 없는 칸을 0으로 친다고 본 것입니다. 오류로 멈춘다고 쓰면 없는 칸을 읽으면 바로 오류가 난다고 본 것입니다(없으면 오류라는 생각). false는 값이 NaN이면 칸이 생기지 않는다고 본 것입니다. 8번 줄도 6~7번 줄처럼 없는 칸을 0으로 바꾼 뒤 더해야 2 2가 찍힙니다.
파이썬에서는 b['모카'] + 1처럼 없는 키를 읽으면 KeyError로 멈춥니다 — 자바스크립트는 없는 칸을 오류 없이 undefined로 읽고, 1을 더하면 NaN이 됩니다.
다시 볼 레슨: 세기: 메뉴별로 모으기 · 객체: 이름 붙은 칸 묶음
문제 7
오늘 마신 물의 양(mL)을 글자로 받아 더합니다. 무엇이 찍힐까요? 세 줄을 글자 그대로 쓰세요.
const water = ['300', '500'];
let total = 0;
let fixed = 0;
for (const ml of water) {
total = total + ml;
fixed = fixed + Number(ml);
}
console.log(total);
console.log(fixed);
console.log(water[1] * 2);
힌트
1번 줄의 칸 값이 따옴표 안에 있는지 보고, 첫 바퀴의 0 + '300'이 무엇인지 적어 보세요.
정답
0300500
800
1000- 1번 줄: 칸 값 '300'과 '500'은 따옴표 안이라 글자입니다.
- 5번 줄: 첫 바퀴의
0 + '300'은 수와 글자라 이어 붙이기가 되어'0300'이고, 둘째 바퀴에'0300500'이 됩니다. - 6번 줄:
Number(ml)이 글자를 수로 바꿔, fixed는 300, 800에 차례로 붙습니다. - 8~9번 줄:
0300500과800을 찍습니다. - 10번 줄:
water[1]은 글자 '500'입니다.*는 이어 붙이는 뜻이 없어 글자를 수로 바꿔 곱하고,1000을 찍습니다.
흔한 오답은 첫 줄을 800이나 300500으로 쓰는 것입니다. 800은 '300'도 수처럼 더해진다고 본 것입니다(문자열과 수를 가리지 않는 생각). 300500은 이어 붙이기는 맞혔지만 시작 값 0을 놓친 것입니다. total을 ''로 시작했다면 300500이 찍힙니다. 글자로 받은 수는 6번 줄처럼 Number()로 바꾼 뒤 더합니다. 셋째 줄을 500500으로 쓰면 *가 글자를 되풀이한다고 본 것입니다. 글자 되풀이는 repeat가 맡습니다.
파이썬에서는 0 + '300'이 TypeError로 멈추고 '500' * 2는 '500500'입니다 — 자바스크립트는 수와 글자를 +로 만나면 오류 없이 글자로 이어 붙이고, *로 만나면 글자를 수로 바꿔 곱합니다.
다시 볼 레슨: 합 모으기와 세기 · 글자를 수로: Number와 NaN · 수·글자·불리언과 typeof
문제 8
카페의 낮 근무와 밤 근무를 맞바꿉니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요. 오류로 멈추면 찍힌 줄 다음에 오류 메시지의 …Error: 줄만 써도 됩니다.
let day = '민호';
let night = '서연';
day, night = night, day;
console.log(day, night);
[day, night] = [night, day];
console.log(day, night);
힌트
3번 줄에서 =의 왼쪽에 오는 것이 night 하나인지, day와 night 둘인지 보세요.
힌트 둘
쉼표와 = 중 무엇이 먼저 묶이는지가 열쇠입니다.
정답
모두 두 줄입니다.
민호 서연
서연 민호- 3번 줄:
=가 쉼표보다 먼저 묶여, 이 줄은day·night = night·day세 식을 차례로 계산합니다. night를 제 값에 다시 붙일 뿐이라 아무것도 바뀌지 않고, 오류도 나지 않습니다. - 4번 줄:
민호 서연을 찍습니다. - 5번 줄: 오른쪽
[night, day]를 먼저 다 계산해 새 배열['서연', '민호']를 만들고, day와 night를 그 칸의 값에 차례로 붙입니다. - 6번 줄:
서연 민호를 찍습니다.
흔한 오답은 서연 민호와 민호 서연을 쓰거나, 3번 줄에서 SyntaxError로 멈춘다고 쓰는 것입니다. 앞의 것은 3번 줄이 두 이름을 맞바꾼다고 본 것이고, 뒤의 것은 쉼표를 이렇게 쓸 수 없다고 본 것입니다. 3번 줄은 오류 없이 지나가 틀린 줄을 알아채기 어렵습니다. 맞바꿀 때는 5번 줄처럼 양쪽을 대괄호로 감쌉니다.
파이썬에서는 day, night = night, day가 두 값을 맞바꿉니다 — 자바스크립트에서는 같은 줄이 아무것도 바꾸지 않으니, [day, night] = [night, day];로 씁니다.
다시 볼 레슨: 구조 분해로 꺼내기
문제 9
손님이 고른 음료에서 겹친 것을 빼 메뉴 가짓수를 봅니다. 무엇이 찍힐까요? 세 줄을 글자 그대로 쓰세요.
const cups =
['녹차', '라테', '녹차', '모카'];
const types = new Set(cups);
const menu = [...types];
console.log(types.length);
console.log(types[1], menu[1]);
console.log(menu.length);
힌트
3번 줄의 types는 배열이 아니라 Set입니다. Set이 값의 수를 무엇으로 알려 주는지, 자리 번호로 꺼낼 수 있는지 떠올려 보세요.
정답
undefined
undefined 라테
3- 3번 줄:
new Set(cups)는 겹친 '녹차'를 한 번만 담아, 녹차 · 라테 · 모카 세 값을 가진 Set을 만듭니다. 값은 처음 본 차례대로 담깁니다. - 4번 줄:
[...types]는 Set의 값을 펼쳐 새 배열['녹차', '라테', '모카']를 만듭니다. - 5번 줄: Set에는
length가 없어undefined입니다. 값의 수는types.size가 셉니다. - 6번 줄: Set은 자리 번호를 붙이지 않아
types[1]은 오류 없이undefined이고, 배열menu[1]은 '라테'입니다. - 7번 줄: menu는 칸이 셋인 배열이라
3입니다.
흔한 오답은 첫 줄을 3으로, 둘째 줄을 라테 라테로, 셋째 줄을 4로 쓰는 것입니다. 3과 라테 라테는 Set도 배열처럼 length와 자리 번호가 있다고 본 것이고, 4는 펼친 배열에 겹친 '녹차'가 다시 들어간다고 본 것입니다. Set의 값을 자리 번호로 꺼내려면 4번 줄처럼 펼쳐 배열로 만듭니다.
파이썬에서는 len(types)로 값의 수를 세고, types[1]처럼 자리 번호로 꺼내면 TypeError로 멈춥니다 — 자바스크립트 Set은 size로 세고, 자리 번호로 읽으면 오류 없이 undefined입니다.
다시 볼 레슨: Map과 Set
문제 10
재고 객체의 칸마다 이름과 개수를 찍으려 합니다. 원두 4와 우유 9 두 줄이 찍혀야 하는데, 아래처럼 5번 줄에서 멈췄습니다. 몇 번 줄의 무엇을 고쳐야 할까요? 한 줄만 고쳐, 고친 줄을 쓰세요.
const stock = {
원두: 4,
우유: 9,
};
for (const k of stock) {
console.log(k, stock[k]);
}
main.js:5for (const k of stock) { ^ TypeError: stock is not iterable at main.js:5:17힌트
오류 메시지의 not iterable은 'stock은 하나씩 꺼낼 수 있는 값이 아니다'라는 뜻입니다. 객체의 키를 하나씩 꺼내는 반복이 무엇이었는지 떠올려 보세요.
정답
5번 줄의 of를 in으로 고쳐 for (const k in stock) {로 씁니다.
const stock = {
원두: 4,
우유: 9,
};
for (const k in stock) {
console.log(k, stock[k]);
}원두 4
우유 9for...of는 배열·문자열처럼 값을 차례로 내주는 반복 가능한(iterable) 값만 돕니다. 중괄호로 만든 객체는 반복 가능한 값이 아니라 5번 줄에서 TypeError로 멈췄고, 앞에서 찍은 줄이 없습니다. 결과에 at main.js:5:17 줄이 있는 것이 실행 중 오류라는 표시입니다. for...in은 객체의 키를 하나씩 꺼내 k를 그 키에 붙이고, 6번 줄의 stock[k]가 그 키의 값을 읽습니다.
- 5번 줄의
stock을Object.keys(stock)으로 바꿔도 맞습니다.Object.keys가 키를 담은 배열['원두', '우유']를 만들어,for...of로 돌 수 있습니다. Object.values(stock)으로 바꾸면 k가 값 4와 9에 붙어4 undefined와9 undefined가 찍힙니다. 6번 줄의stock[4]가 없는 키를 읽기 때문입니다.- 5번 줄에서
k를[k, v]로,stock을Object.entries(stock)으로 함께 바꿔도 맞습니다. 키와 값의 쌍을 풀어 k가 키에 붙습니다(구조 분해로 꺼내기). k는 그대로 두고stock만Object.entries(stock)으로 바꾸면 k가['원두', 4]같은 배열에 붙어[ '원두', 4 ] undefined처럼 찍힙니다.
파이썬에서는 for k in stock:이 딕셔너리의 키를 꺼냅니다 — 자바스크립트는 객체를 for...of로 돌 수 없고, 키는 for...in으로 꺼냅니다.
다시 볼 레슨: 객체 돌기 · for...of로 배열 돌기
문제 11 (만들어 보기)
주문 목록 orders에서 결제 방법 pay별로 주문이 몇 건인지 세어 객체 sold에 모읍니다. 뼈대의 마지막 세 줄이 이렇게 찍어야 합니다.
카드 2
현금 1
세 주문의 pay를 모두 '카드'로 바꾸면 이렇게 나와야 합니다.
카드 3
아래 뼈대에서 1~5번 줄과 마지막 세 줄은 그대로 두고, 주석 둘 아래를 채우세요. 다 쓰면 둘째 시험 값으로도 따라가 봅니다.
const orders = [
{ item: '빵', pay: '카드' },
{ item: '차', pay: '현금' },
{ item: '잼', pay: '카드' },
];
// 1. 빈 객체 만들기
// 2. 하나씩 꺼내 칸 올리기
for (const k in sold) {
console.log(k, sold[k]);
}
힌트
2번 주석 아래에는 for...of로 주문을 하나씩 꺼내, 그 주문의 pay 값을 키로 쓰는 칸을 1 올립니다. 처음 만나는 결제 방법은 칸이 없으니 0으로 쳐서 더합니다.
정답
모범 답입니다.
const orders = [
{ item: '빵', pay: '카드' },
{ item: '차', pay: '현금' },
{ item: '잼', pay: '카드' },
];
// 1. 빈 객체 만들기
const sold = {};
// 2. 하나씩 꺼내 칸 올리기
for (const o of orders) {
const n = sold[o.pay] ?? 0;
sold[o.pay] = n + 1;
}
for (const k in sold) {
console.log(k, sold[k]);
}카드 2
현금 1세 pay를 모두 '카드'로 바꾸면 반복이 '카드' 칸만 세 번 올립니다. '현금' 칸은 한 번도 생기지 않아, 마지막 반복이 카드 3 한 줄만 찍습니다.
- 다르게 써도 되는 곳:
?? 0대신|| 0으로 써도 여기서는 같게 찍힙니다. 이름 o는order처럼 달라도 되고,for (const { pay } of orders)로 꺼내sold[pay]로 써도 됩니다. - 찍은 화면이 위와 같고 둘째 시험 값에서도
카드 3한 줄이 나오면 맞습니다. - 흔한 오답:
- sold를 처음부터
{ 카드: 0, 현금: 0 }으로 만들어 두면 처음 시험 값은 맞지만, 둘째 시험 값에서현금 0줄이 더 찍힙니다. 세는 칸은 처음 만날 때 만듭니다. const sold = {};를 반복 안에 두면 sold가 반복의 중괄호 안에서만 살아, 마지막 반복에서ReferenceError로 멈춥니다(규칙 4).let sold = {};를 반복 앞에 두고 반복 안에서sold = {};로 다시 비우면 바퀴마다 칸이 사라져, 마지막 주문의카드 1만 찍힙니다.sold.pay로 쓰면 결제 방법이 아니라 이름이 pay인 칸 하나를 올려pay 3이 찍힙니다.?? 0없이sold[o.pay] + 1을 넣으면 없는 칸의undefined에 1을 더해카드 NaN과현금 NaN이 찍힙니다.
- sold를 처음부터
다시 볼 레슨: 세기: 메뉴별로 모으기 · 객체를 담은 배열 · 객체 돌기
문제 12 (만들어 보기)
이번에는 빈 데서 씁니다. 성적 앱이 학생 한 명의 성적을 JSON 글 text로 받았습니다. text를 객체로 바꾼 뒤 이름 name과 나머지 과목 점수를 나누고, 과목 점수의 평균을 구해 이름과 평균을 빈칸 하나로 이어 한 줄로 찍습니다. 이렇게 나와야 합니다.
하은 85
4번 줄을 "eng": 80,으로 바꾸고 그 아래에 "sci": 70 줄을 더하면 이렇게 나와야 합니다.
하은 80
아래 칸의 1~5번 줄은 그대로 두고, 그 아래를 씁니다.
const text = `{
"name": "하은",
"kor": 90,
"eng": 80
}`;
힌트
하위 목표 셋으로 나눠 씁니다 — 1. 글을 객체로 바꿔 이름과 나머지 나누기 · 2. 나머지 칸을 하나씩 꺼내 합과 개수 모으기 · 3. 끝나고 쓰기.
정답
모범 답입니다.
const text = `{
"name": "하은",
"kor": 90,
"eng": 80
}`;
const { name, ...scores } =
JSON.parse(text);
let sum = 0;
let n = 0;
for (const key in scores) {
sum = sum + scores[key];
n = n + 1;
}
console.log(name, sum / n);하은 856~7번 줄이 하위 목표 1, 8~13번 줄이 2, 14번 줄이 3입니다. JSON.parse가 글을 객체로 바꾸고, ...scores가 name을 뺀 나머지 칸을 새 객체 { kor: 90, eng: 80 }에 모읍니다. 반복이 두 바퀴 돌아 sum은 170, n은 2입니다.
둘째 시험 값에서는 scores가 { kor: 90, eng: 80, sci: 70 }이 되어 반복이 세 바퀴 돕니다. sum은 240, n은 3이라 하은 80이 찍힙니다. 4번 줄 끝에 쉼표를 빠뜨리면 JSON 글이 틀려 JSON.parse가 SyntaxError로 멈춥니다.
- 다르게 써도 되는 곳:
Object.values(scores)로 점수만 담은 배열을 만들고for...of로 더한 뒤, 그 배열의length로 나눠도 됩니다.JSON.parse(text)에 이름을 먼저 붙이고 다음 줄에서 나눠도 됩니다. 이름은rest·total처럼 달라도 됩니다. - 찍은 화면이 위와 같고 둘째 시험 값에서도
하은 80이 나오면 맞습니다. - 흔한 오답:
- 과목 수를 세지 않고
sum / 2로 나누면 처음 시험 값은 맞지만, 둘째 시험 값에서하은 120이 찍힙니다. 과목이 몇 개인지는 반복에서 셉니다. - scores를
for...of로 돌면scores is not iterable이라는TypeError로 멈춥니다. 객체의 키는for...in으로 꺼냅니다. JSON.parse없이 text를 그대로 나누면 글에는 name 칸이 없어 name이undefined이고, 나머지도 점수가 아니라 글자라undefined NaN이 찍힙니다.- 나누지 않고 name까지 든 객체 전체를 돌면 첫 바퀴의
0 + '하은'이 이어 붙이기가 되어하은 NaN이 찍힙니다.
- 과목 수를 세지 않고
다시 볼 레슨: JSON: 객체와 글 사이 · 단축 속성과 나머지 모으기 · 객체 돌기
틀린 문제는 그 레슨으로 돌아가 모션 그림과 '자주 틀리는 곳'을 보고, 하루쯤 지난 뒤 그 문제만 다시 풀어 보세요. 그날 바로 다시 풀면 방금 본 정답이 기억나 맞힌 것인지 알기 어렵습니다.