본문으로 건너뛰기

단원 연습 문제

자바스크립트 목차객체문제 12개

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
우유 9

for...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이 찍힙니다.

다시 볼 레슨: 세기: 메뉴별로 모으기 · 객체를 담은 배열 · 객체 돌기

문제 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);
실행 결과
하은 85

6~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: 객체와 글 사이 · 단축 속성과 나머지 모으기 · 객체 돌기


틀린 문제는 그 레슨으로 돌아가 모션 그림과 '자주 틀리는 곳'을 보고, 하루쯤 지난 뒤 그 문제만 다시 풀어 보세요. 그날 바로 다시 풀면 방금 본 정답이 기억나 맞힌 것인지 알기 어렵습니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

자바스크립트 목차로