본문으로 건너뛰기

for의 세 칸

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

목차

for 문은 반복에 필요한 시작 · 조건 · 바꾸기를 머리 한 줄의 세 칸에 모아 씁니다. 시작 칸은 처음에 한 번, 조건 칸은 바퀴마다 덩어리 앞에서, 바꾸기 칸은 바퀴마다 덩어리 뒤에서 실행됩니다.

while로 1부터 3까지 세려면 시작 값 두기, 조건, 1 더하기를 서로 다른 줄에 써야 합니다. 하나만 빠뜨려도 반복이 끝나지 않거나 틀린 수를 셉니다. for는 이 셋을 한 줄에 모아 빠뜨리기 어렵게 합니다. 대신 세 칸이 실행되는 차례를 익혀야 합니다.

13단계 중 1단계. 1번 줄 머리에 칸이 셋(시작 · 조건 · 바꾸기) 있습니다. 칸이 실행되는 차례를 따라갑니다.

1세 칸에 반복의 일을 모은다

앞 레슨의 while로 1부터 3까지 찍는 코드입니다. 반복의 일이 세 줄에 흩어져 있습니다.

let i = 1;
while (i < 4) {
  console.log(i);
  i = i + 1;
}
실행 결과
1
2
3

같은 일을 for로 쓰면 이렇습니다. for 다음 괄호 안에 세 칸을 세미콜론으로 나눠 씁니다.

for (let i = 1; i < 4; i++) {
  console.log(i);
}
실행 결과
1
2
3

세 칸이 while 코드의 어느 줄인지 견주면 이렇습니다.

칸for 코드while 코드에서
시작let i = 11번 줄
조건i < 42번 줄
바꾸기i++4번 줄 i = i + 1;

i++는 i에 1을 더한 값에 i를 다시 붙이는 줄임 꼴로, i = i + 1과 같습니다. 반복을 세는 이름은 흔히 i로 씁니다.

2세 칸이 실행되는 차례

세 칸은 쓴 차례대로 한 번씩 실행되지 않습니다.

  1. 시작 칸: 반복에 들어설 때 한 번만 실행합니다.
  2. 조건 칸: 바퀴마다 덩어리 앞에서 봅니다. true면 덩어리를 실행하고, false면 반복이 끝납니다.
  3. 바꾸기 칸: 덩어리를 다 실행한 뒤에 실행하고, 다시 조건 칸으로 갑니다.

바꾸기 칸은 머리에 쓰여 있지만 덩어리 뒤에 실행됩니다. while 코드에서 1 더하기가 덩어리 끝에 있던 것과 같습니다. 추적 표에는 for 줄의 칸이 실행될 때마다 한 줄을 씁니다. 시작 · 바꾸기 칸은 바뀐 이름과 값을, 조건 칸은 조건과 true·false를 씁니다.

줄바뀐 이름값출력
1i1
1조건 i < 4true
21
1i2
1조건 i < 4true
22
1i3
1조건 i < 4true
23
1i4
1조건 i < 4false

마지막으로 조건을 볼 때 i는 4입니다. 4 < 4가 false라서 반복이 끝나고, 4는 찍히지 않습니다.

이번에는 시작을 0으로, 조건을 i < 3으로 바꿨습니다. 무엇이 찍힐지 정한 뒤 펼쳐 보세요.

for (let i = 0; i < 3; i++) {
  console.log(i);
}
실행 결과 보기
실행 결과
0
1
2

예상과 다르면 그곳이 배울 곳입니다. i가 3이 되면 3 < 3이 false라서 3은 찍히지 않습니다. 0부터 세면 i < 3으로 세 번, i < n으로 n번 돕니다.

3반복 머리의 i는 중괄호 안에서만 산다

반복이 끝난 뒤 i를 찍으려 합니다. 4번 줄은 무엇을 찍을까요?

for (let i = 0; i < 3; i++) {
  console.log('커피');
}
console.log(i);
실행 결과 보기
실행 결과
커피커피커피main.js:4console.log(i);            ^ ReferenceError: i is not defined    at main.js:4:13

예상과 다르면 그곳이 배울 곳입니다. ReferenceError 줄의 i is not defined는 'i가 정의되어 있지 않다', 곧 4번 줄에는 그런 이름이 없다는 뜻입니다. 반복은 세 번 돌아 커피를 찍었지만, i는 반복의 중괄호를 나가며 사라졌습니다.

if와 else에서 덩어리 안의 let 이름이 밖에 없던 것처럼, for 머리에서 let으로 만든 i도 그 반복의 중괄호 안에서만 삽니다. 규칙 4의 마지막 말이 이것입니다.

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

반복이 끝난 뒤에도 쓸 값에는 반복 앞에서 만든 이름을 붙여 둡니다. 다음 레슨의 합 모으기가 이 꼴입니다.

예제

대기 번호 부르기

주문한 음료가 나오면 대기 번호를 차례로 부릅니다. 템플릿 문자열의 ${n} 자리에 바퀴마다 다른 번호가 들어갑니다.

for (let n = 1; n < 4; n++) {
  console.log(`${n}번 손님`);
}
실행 결과
1번 손님
2번 손님
3번 손님

자주 틀리는 곳

틀린 생각: 글자 수가 2이면 번호 2까지 돌아야 마지막 글자에 닿는다.

'두 글자를 다 본다'고 말하면 1, 2를 세니, 글자 수까지 도는 i <= n이 맞아 보입니다. 그러나 글자 자리 번호는 0부터라(인덱스와 자르기) 마지막 글자의 번호는 1입니다.

const word = '라테';
const n = word.length;
for (let i = 0; i <= n; i++) {
  console.log(i, word[i]);
}
실행 결과
0 라
1 테
2 undefined

마지막 바퀴의 word[2]는 칸 밖이라 오류 없이 undefined를 꺼냅니다. 조건이 i < n이면 0 라와 1 테 두 줄만 찍힙니다.

맞는 규칙: 0부터 셀 때 n번 도는 조건은 i < n입니다. <= 연산자를 쓰면 한 바퀴 더 돌아, 글자 번호로 돌 때는 칸 밖의 undefined를 꺼냅니다.

틀린 생각: for 머리 끝에 세미콜론을 붙여도 중괄호 덩어리가 되풀이된다.

문장 끝마다 세미콜론을 붙이는 습관대로 for (…);처럼 쓰기 쉽습니다. 그러면 세미콜론 하나가 빈 문장이 되어 반복은 아무것도 하지 않고 돈 뒤 끝나고, 중괄호 덩어리는 그 뒤에 한 번 실행됩니다.

for (let i = 0; i < 3; i++); {
  console.log('커피');
}
실행 결과
커피

맞는 규칙: for (…) 바로 뒤의 세미콜론은 반복이 되풀이할 빈 문장이라, 아래 중괄호 덩어리는 반복 밖이 됩니다. for 머리는 닫는 괄호 뒤에 바로 여는 중괄호를 둡니다(규칙 4).

틀린 생각: 덩어리 안에서 i를 바꾸지 않으니 반복 머리에 const i를 써도 된다.

바꾸지 않을 이름은 const로 만든다고 배워서, 덩어리 안에서 다시 붙이지 않는 i도 그래 보입니다. 그러나 바꾸기 칸 i++가 바퀴마다 i를 다시 붙입니다.

for (const i = 0; i < 3; i++) {
  console.log(i);
}
실행 결과
0main.js:1for (const i = 0; i < 3; i++) {                          ^ TypeError: Assignment to constant variable.    at main.js:1:27

첫 바퀴는 0을 찍고, 바꾸기 칸에서 const 이름을 다시 붙이려다 멈춥니다. ^ 표시가 i++를 가리킵니다.

맞는 규칙: 바꾸기 칸은 바퀴마다 i를 다시 붙이고 const 이름은 다시 붙일 수 없어서, 셈하는 이름은 let으로 만듭니다(규칙 3).

틀린 생각: 반복이 끝나도 i는 마지막 값에 붙은 채 남는다.

반복이 끝나도 프로그램은 이어지니, i가 마지막으로 센 값에 붙은 채 남아 있을 것 같습니다. 3절 코드는 4번 줄에서 i is not defined로 멈췄습니다.

맞는 규칙: for 머리에서 let으로 만든 이름은 그 반복 안에서만 삽니다. 반복 뒤에도 쓸 값에는 반복 앞에서 만든 이름을 붙여 둡니다(규칙 4).

확인 문제

1. 예제(대기 번호)의 시작과 조건을 바꿨습니다. 무엇이 찍히는지 마지막 줄까지 그대로 쓰세요.

for (let n = 2; n < 5; n++) {
  console.log(`${n}번 손님`);
}
힌트

n이 바퀴마다 붙는 값을 적고, 조건 n < 5가 언제 false가 되는지 봅니다.

정답
실행 결과
2번 손님
3번 손님
4번 손님

n은 2, 3, 4일 때 덩어리를 실행하고, 5가 되면 5 < 5가 false라 반복이 끝납니다.

흔한 오답은 넷째 줄 5번 손님까지 쓰는 것입니다. 조건의 끝 수도 든다고 본 것입니다(끝도 든다는 생각).

2. 아래 while 코드는 5, 6, 7을 줄마다 찍습니다.

let n = 5;
while (n < 8) {
  console.log(n);
  n = n + 1;
}

같은 출력이 나오도록 for 머리의 빈칸 둘을 채우세요.

for (let n = __; n < __; n++) {
  console.log(n);
}
힌트

while 코드의 1번 줄이 시작 칸, 2번 줄이 조건 칸입니다.

정답

차례로 5와 8입니다. 다 채우면 for (let n = 5; n < 8; n++) {⁠입니다.

while의 조건 n < 8이 8을 넣지 않듯, for의 조건 칸도 같습니다.

흔한 오답은 둘째 빈칸에 7을 쓰는 것입니다. 마지막에 찍는 7을 끝 자리에 써서 끝 수도 든다고 본 것입니다(끝도 든다는 생각). n < 7이면 5와 6만 찍힙니다.

3. 하루에 5000걸음씩 걷습니다. 날마다 그날까지 걸은 걸음 수를 찍는 코드입니다. 줄마다 찍히는 값을 고르세요.

for (let i = 1; i <= 3; i++) {
  console.log(i * 5000);
}
  • ① 5000, 10000
  • ② 5000, 10000, 15000
  • ③ 0, 5000, 10000
힌트

조건이 < 연산자가 아니라 <= 연산자입니다. i가 3일 때 조건을 따져 봅니다.

정답
실행 결과
5000
10000
15000

②입니다. 3 <= 3은 true라서 셋째 바퀴도 돕니다. i가 4가 되어서야 4 <= 3이 false입니다.

  • ① <= 연산자를 < 연산자처럼 읽어 3일 때 멈춘다고 봤습니다. <= 연산자는 같을 때도 true입니다.
  • ③ 반복이 늘 0부터 센다고 봤습니다. 시작 칸이 let i = 1이라 1부터입니다.

컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요. 1절의 for 코드(세 줄)를 main.js에 저장해 돌립니다. 그다음 1번 줄의 i < 4를 i <= 4로 바꾸면 무엇이 찍힐지 먼저 적고, 바꿔 돌려서 맞춰 봅니다. 저장하고 돌리는 법은 내 컴퓨터에서 돌려 보기에 있습니다.

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

자바스크립트 목차로