본문으로 건너뛰기

while과 추적 표

자바스크립트 목차반복레슨 20 / 76

목차

while 문은 조건이 참인 동안 중괄호 덩어리를 되풀이합니다. 조건은 덩어리를 시작할 때마다 다시 봅니다.

if 문은 덩어리를 한 번 실행할지 고를 뿐이라, 손님 번호를 1부터 100까지 부르려면 console.log를 100줄 써야 합니다. while 문은 덩어리 하나를 되풀이해 이 일을 몇 줄로 끝냅니다. 같은 줄이 여러 번 실행되면 따라가기 어려워서, 실행된 줄을 차례로 적는 추적 표(trace table)도 함께 배웁니다.

이 단원(반복)을 이미 안다면 단원 연습 문제부터 풀고 틀린 레슨만 보세요. 건너뛸지 볼 때는 힌트를 펴지 않고 풉니다.

파이썬을 배웠다면 — 이 단원에서 다른 곳

파이썬을 배웠다면 이 단원에서 다른 곳: for (let i …)의 i는 반복 밖에 없음(for의 세 칸) · 틀린 값이 NaN·undefined로 오류 없이 나옴 — 찍어 보며 찾는 차례는 파이썬과 같음(값을 찍어 보며 고치기).

14단계 중 1단계. 다음을 누르면 1번 줄부터 한 줄씩 실행합니다. 줄이 실행될 때마다 추적 표에 한 줄이 쌓입니다.

1조건이 참인 동안 되풀이하는 while

while 문은 if 문과 꼴이 같습니다. while 다음 괄호 안에 조건을 쓰고, 되풀이할 줄을 중괄호로 묶어 덩어리를 만듭니다.

let n = 0;
while (n < 3) {
  n = n + 1;
  console.log(n);
}
console.log('끝');
실행 결과
1
2
3
끝

자바스크립트는 이 코드를 이렇게 실행합니다.

  1. 1번 줄: 이름 n을 만들어 0에 붙입니다.
  2. 2번 줄: 조건 n < 3을 봅니다. 0 < 3은 true라서 덩어리로 들어갑니다.
  3. 3~4번 줄: 덩어리를 한 번 실행합니다. n이 1에 다시 붙고, 1이 찍힙니다.
  4. 닫는 중괄호(5번 줄)에 닿으면 2번 줄로 돌아가 조건을 다시 봅니다.
  5. 조건이 false면 덩어리를 건너뛰고 6번 줄로 갑니다.

덩어리를 한 번 실행하는 것을 한 바퀴라고 부릅니다. 이 코드는 세 바퀴를 돈 뒤 끝을 찍습니다. if와 else에서 세운 규칙 4에 반복 쪽을 더하면 이렇습니다.

규칙 4. 들여쓰기가 아니라 중괄호가 덩어리를 정합니다. if는 덩어리를 한 번 실행할지 고르고, for·while은 덩어리를 되풀이합니다. 조건은 덩어리를 시작할 때마다 봅니다.

2조건은 덩어리를 시작할 때만 본다

이번에는 n이 첫 바퀴에서 단번에 3을 넘습니다. 3번 줄에서 조건이 거짓이 되는데, 4번 줄도 실행될까요? 무엇이 찍힐지 정한 뒤 펼쳐 보세요.

let n = 0;
while (n < 3) {
  n = n + 5;
  console.log(n);
}
실행 결과 보기
실행 결과
5

예상과 다르면 그곳이 배울 곳입니다. 3번 줄에서 n이 5에 붙어 조건이 거짓이 되어도, 이 바퀴는 4번 줄까지 마저 실행해 5를 찍습니다. 다시 2번 줄에 와서야 5 < 3이 false라서 반복이 끝납니다.

1절 코드의 셋째 바퀴도 같아서, n이 3에 붙은 뒤에도 4번 줄이 3을 찍습니다. while 문은 조건을 늘 지켜보지 않고, 2번 줄에 올 때, 곧 덩어리를 시작할 때만 봅니다.

3추적 표로 한 줄씩 따라가기

추적 표는 실행되는 줄을 차례로 적는 표입니다. 칸은 넷입니다 — 줄, 바뀐 이름, 값, 출력. 쓰는 규칙도 넷입니다.

  • 줄이 하나 실행될 때마다 표에 한 줄을 씁니다. 같은 줄이 다시 실행되면 다시 씁니다.
  • 이름을 붙이는 줄은 바뀐 이름과 새 값을 씁니다.
  • while 줄은 이름을 바꾸지 않습니다. 바뀐 이름 칸에 조건을, 값 칸에 true·false를 씁니다.
  • console.log 줄은 찍힌 글자를 출력 칸에 씁니다.

닫는 중괄호만 있는 줄은 실행되는 줄이 아니라서 표에 쓰지 않습니다. 1절 코드를 추적 표로 따라가면 이렇습니다.

줄바뀐 이름값출력
1n0
2조건 n < 3true
3n1
41
2조건 n < 3true
3n2
42
2조건 n < 3true
3n3
43
2조건 n < 3false
6끝

출력 칸을 위에서 아래로 읽으면 실행 결과와 같습니다. 조건이 true인 줄이 셋이니 세 바퀴입니다. 조건 줄을 빼면 바퀴 수를 하나 틀리기 쉽습니다. 표는 끝까지 씁니다. 반만 쓴 표는 안 쓴 것과 같습니다.

4끝나지 않는 반복

1절 코드에서 3번 줄 n = n + 1;을 빠뜨리면 아래 코드가 됩니다. 끝나지 않는 코드라서 실행 결과 대신 추적 표로 봅니다.

let n = 0;
while (n < 3) {
  console.log(n);
}
console.log('끝');
줄바뀐 이름값출력
1n0
2조건 n < 3true
30
2조건 n < 3true
30
…

n이 늘 0이라서 2번 줄의 조건은 늘 true이고, 0이 끝없이 찍힙니다. 5번 줄의 끝은 끝내 찍히지 않습니다. 사람은 'n이 3보다 작은 동안 불러라'를 들으면 알아서 수를 늘려 가지만, 자바스크립트는 쓴 줄만 실행합니다. 반복을 쓰면 덩어리 안에 조건의 이름을 바꾸는 줄이 있는지 먼저 봅니다. 이미 돌고 있는 반복은 터미널에서 Ctrl+C를 눌러 멈춥니다. Node는 오류 메시지 없이 멈춥니다.

예제

쿠키를 몇 개 살 수 있을까

7000원으로 2000원짜리 쿠키를 몇 개 사고 얼마가 남는지 셉니다. 남은 돈이 2000원 이상인 동안 하나씩 삽니다. 이렇게 몇 번 되풀이할지가 처음 가진 돈에 따라 달라지는 일에 while을 씁니다.

let money = 7000;
let count = 0;
while (money >= 2000) {
  money = money - 2000;
  count = count + 1;
}
console.log(count, money);
실행 결과
3 1000

세 바퀴를 돌고 나면 money가 1000이라 3번 줄의 조건 1000 >= 2000이 false입니다. 쿠키는 3개, 남은 돈은 1000원입니다.

덩어리를 닫지 않으면

1절 코드에서 덩어리를 닫는 5번 줄을 지웠습니다.

let n = 0;
while (n < 3) {
  n = n + 1;
  console.log(n);
console.log('끝');
실행 결과
main.js:6   SyntaxError: Unexpected end of input

SyntaxError로 시작하는 줄부터 읽습니다. Unexpected end of input⁠은 '뜻밖에 입력이 끝났다', 곧 2번 줄에서 연 덩어리를 닫지 않은 채 파일이 끝났다는 뜻입니다. 맨 위 main.js:6은 코드에 없는 6번 줄, 곧 파일 끝입니다. 파일 끝에 줄바꿈이 없으면 마지막 줄 번호 main.js:5와 그 줄 코드가 찍히는데, 어느 쪽이든 파일의 끝을 가리킵니다. 닫는 중괄호가 없다는 것을 파일 끝까지 읽고서야 알아서, 오류 자리가 고칠 곳(4번 줄 다음)보다 늦게 나옵니다. 문법 오류라 1번 줄도 실행되지 않았습니다.

자주 틀리는 곳

틀린 생각: 조건이 거짓이 되는 순간 반복이 멈춘다.

while은 '~하는 동안'이라는 뜻이라, 조건을 쉬지 않고 지켜본다고 여기기 쉽습니다. 2절에서 보았듯 자바스크립트는 조건을 2번 줄에 올 때만 봅니다.

맞는 규칙: while 조건은 덩어리를 시작할 때만 봅니다. 그래서 덩어리 가운데서 조건이 거짓이 되어도 그 바퀴는 끝까지 실행합니다(규칙 4).

틀린 생각: while 자리에 if를 써도 덩어리가 되풀이된다.

if 문과 while 문은 괄호 속 조건과 중괄호 덩어리까지 꼴이 같습니다. 꼴은 같아도 if는 조건으로 되돌아가지 않습니다.

1절 코드의 2번 줄에서 while만 if로 바꾸면 1과 끝 두 줄만 찍힙니다. 덩어리를 한 번 실행한 뒤 2번 줄로 돌아가지 않고 6번 줄로 내려가기 때문입니다.

맞는 규칙: if는 조건을 한 번 보고 덩어리를 많아야 한 번 실행합니다. 되풀이는 while이 합니다(규칙 4).

확인 문제

1. 예제의 첫 줄을 let money = 6000;으로 바꿨습니다. 무엇이 찍히는지 그대로 쓰세요.

let money = 6000;
let count = 0;
while (money >= 2000) {
  money = money - 2000;
  count = count + 1;
}
console.log(count, money);
힌트

3번 줄의 조건을 바퀴마다 봅니다. money가 2000인 바퀴에서 >= 연산자를 따져 봅니다.

정답
실행 결과
3 0

money는 6000 → 4000 → 2000 → 0으로 바뀝니다. 셋째 바퀴를 시작할 때 2000 >= 2000은 true라서 한 번 더 삽니다. 넷째 바퀴를 시작할 때 0 >= 2000이 false라 반복이 끝납니다.

흔한 오답은 2 2000입니다. >= 연산자를 '보다 크다'로 읽어 2000일 때 멈춘다고 본 것입니다.

2. 1번 코드를 추적 표로 따라갑니다. 표의 (가)~(라)를 채우세요. 줄 칸은 실행된 줄의 번호입니다.

줄바뀐 이름값출력
1money6000
2count0
3조건 money >= 2000true
4money4000
5count1
3조건 money >= 2000true
4money2000
5count2
3조건 money >= 2000(가)
(나)money0
5count3
3조건 money >= 2000(다)
(라)3 0
힌트

앞 바퀴들에서 줄 칸이 어떤 차례로 되풀이되는지 봅니다.

정답

(가) true · (나) 4 · (다) false · (라) 7

(가)는 2000 >= 2000이라 true입니다. (나)는 셋째 바퀴의 4번 줄입니다. (다)는 0 >= 2000이라 false이고, 반복을 빠져나가 7번 줄이 3 0을 찍습니다.

흔한 오답은 (라)에 6을 쓰는 것입니다. 6번 줄은 닫는 중괄호뿐이라 실행되는 줄이 아닙니다. 손으로 쓸 때 또 흔히 빠뜨리는 줄이 (다)입니다. 마지막에 조건을 본 줄도 실행된 줄이라 한 줄을 씁니다.

3. 하루에 4000걸음씩 걸어 10000걸음을 채우려 합니다. 이 코드가 찍는 값을 마지막 줄까지 줄마다 쓰세요.

let steps = 0;
while (steps < 10000) {
  steps = steps + 4000;
  console.log(steps);
}
힌트

추적 표에 바퀴마다 2번 줄의 조건과 steps 값을 적어 봅니다.

정답

모두 세 줄입니다.

실행 결과
4000
8000
12000

셋째 바퀴를 시작할 때 8000 < 10000은 true라서 덩어리로 들어갑니다. 3번 줄에서 12000이 되어 조건이 거짓이 되어도 4번 줄까지 마저 실행합니다.

흔한 오답은 4000과 8000 두 줄만 쓴 답입니다. 조건이 거짓이 되는 순간 반복이 멈춘다고 본 것입니다(조건을 늘 지켜본다는 생각). 조건은 바퀴를 시작할 때만 봅니다. 4000 한 줄만 쓰면 덩어리를 한 번만 실행한다고 본 것입니다. 한 번 고르는 것은 if이고, while은 되풀이합니다.

컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요. 1절 코드(여섯 줄)를 main.js에 저장해 돌립니다. 그다음 3번 줄 n = n + 1;을 4번 줄 console.log(n); 아래로 옮기면 무엇이 찍힐지 먼저 적고, 옮겨 돌려서 맞춰 봅니다. 저장하고 돌리는 법은 내 컴퓨터에서 돌려 보기에 있습니다.

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

자바스크립트 목차로