for 문은 반복에 필요한 시작 · 조건 · 바꾸기를 머리 한 줄의 세 칸에 모아 씁니다. 시작 칸은 처음에 한 번, 조건 칸은 바퀴마다 덩어리 앞에서, 바꾸기 칸은 바퀴마다 덩어리 뒤에서 실행됩니다.
while로 1부터 3까지 세려면 시작 값 두기, 조건, 1 더하기를 서로 다른 줄에 써야 합니다. 하나만 빠뜨려도 반복이 끝나지 않거나 틀린 수를 셉니다. for는 이 셋을 한 줄에 모아 빠뜨리기 어렵게 합니다. 대신 세 칸이 실행되는 차례를 익혀야 합니다.
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 = 1 | 1번 줄 |
| 조건 | i < 4 | 2번 줄 |
| 바꾸기 | i++ | 4번 줄 i = i + 1; |
i++는 i에 1을 더한 값에 i를 다시 붙이는 줄임 꼴로, i = i + 1과 같습니다. 반복을 세는 이름은 흔히 i로 씁니다.
2세 칸이 실행되는 차례
세 칸은 쓴 차례대로 한 번씩 실행되지 않습니다.
- 시작 칸: 반복에 들어설 때 한 번만 실행합니다.
- 조건 칸: 바퀴마다 덩어리 앞에서 봅니다.
true면 덩어리를 실행하고,false면 반복이 끝납니다. - 바꾸기 칸: 덩어리를 다 실행한 뒤에 실행하고, 다시 조건 칸으로 갑니다.
바꾸기 칸은 머리에 쓰여 있지만 덩어리 뒤에 실행됩니다. while 코드에서 1 더하기가 덩어리 끝에 있던 것과 같습니다.
추적 표에는 for 줄의 칸이 실행될 때마다 한 줄을 씁니다. 시작 · 바꾸기 칸은 바뀐 이름과 값을, 조건 칸은 조건과 true·false를 씁니다.
| 줄 | 바뀐 이름 | 값 | 출력 |
|---|---|---|---|
| 1 | i | 1 | |
| 1 | 조건 i < 4 | true | |
| 2 | 1 | ||
| 1 | i | 2 | |
| 1 | 조건 i < 4 | true | |
| 2 | 2 | ||
| 1 | i | 3 | |
| 1 | 조건 i < 4 | true | |
| 2 | 3 | ||
| 1 | i | 4 | |
| 1 | 조건 i < 4 | false |
마지막으로 조건을 볼 때 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로 바꾸면 무엇이 찍힐지 먼저 적고, 바꿔 돌려서 맞춰 봅니다.
저장하고 돌리는 법은 내 컴퓨터에서 돌려 보기에 있습니다.