학습 자료

반복문 — 같은 일을 백 번 시킨다


Article

1부터 100까지 더하라고 하면 어떻게 할까. 1 + 2 + 3 + ...을 손으로 다 쓸 수는 없다.

컴퓨터가 사람보다 압도적으로 잘하는 일이 바로 이것이다. 지치지 않고 같은 일을 반복하기. 그 명령이 반복문이다.

for — 몇 번 반복할지 알 때

가장 많이 쓰는 반복문이다. 괄호 안에 세 가지를 세미콜론으로 구분해 넣는다.

for (let i = 0; i < 3; i++) {
  console.log(`${i}번째`);
}
콘솔
  • 0번째
  • 1번째
  • 2번째

세 자리가 각각 무슨 일을 하는지 뜯어본다.

for 괄호 안의 세 자리
  1. let i = 0초기화 — 딱 한 번
  2. i < 3조건 — 매번 검사
  3. i++증감 — 본문 뒤에

실행 순서가 직관과 조금 다르다. 증감식은 본문을 실행한 뒤에 돌아간다.

i = 0 부터 세 번 도는 과정
  1. 01

    초기화 — 한 번만

    i0 으로 만든다. 반복하는 동안 다시 실행되지 않는다.

    let i = 0;
  2. 02

    조건 검사

    0 < 3 은 참이다. 본문으로 들어간다.

    i < 3true
  3. 03

    본문 실행

    0번째 를 출력한다.

    console.log(`${i}번째`);
  4. 04

    증감

    이제야 i1 이 된다. 그리고 2번으로 돌아가 조건을 다시 검사한다.

    i++  →  i 는 1
  5. 05

    조건이 거짓이 되면 끝

    i3 이 되면 3 < 3 이 거짓이라 본문에 들어가지 않고 반복이 끝난다.

그래서 i0, 1, 2까지만 쓰이고 3에서는 본문이 실행되지 않는다. i < 3이면 세 번 돈다.

0부터 세는 이유

i = 0으로 시작하는 게 어색할 수 있다. 하지만 5강에서 본 것처럼 인덱스가 0부터 시작하므로, 배열과 짝을 맞추면 자연스러워진다.

const fruits = ["사과", "바나나", "포도"];

for (let i = 0; i < fruits.length; i++) {
  console.log(i, fruits[i]);
}
콘솔
  • 0 '사과'
  • 1 '바나나'
  • 2 '포도'

fruits.length가 3이고 마지막 인덱스는 2다. i < fruits.length라고 쓰면 정확히 맞아떨어진다. i <= fruits.length라고 쓰면 마지막에 fruits[3]을 읽어 undefined가 나온다.

값을 쌓아간다

반복문 바깥에 변수를 두고 안에서 더하는 패턴이 기본이다.

let total = 0;

for (let i = 1; i <= 100; i++) {
  total += i;
}

console.log(total);
콘솔
  • 5050

total을 밖에 선언한 게 중요하다. 안에 선언하면 매 회차마다 새로 만들어져 값이 쌓이지 않는다.

구구단도 같은 방식이다.

const dan = 2;

for (let i = 1; i <= 5; i++) {
  console.log(`${dan} × ${i} = ${dan * i}`);
}
2단의 결과가 자라는 모양
2 × 12
2 × 24
2 × 36
2 × 48
2 × 510

while — 몇 번일지 모를 때

조건이 참인 동안 계속 돈다. 횟수가 정해져 있지 않을 때 쓴다.

let count = 3;

while (count > 0) {
  console.log(count);
  count--;
}

console.log("발사");
콘솔
  • 3
  • 2
  • 1
  • 발사

for와 달리 초기화와 증감을 직접 챙겨야 한다. count--를 빠뜨리면 조건이 영원히 참이라 프로그램이 멈추지 않는다.

do...while도 있다. 조건을 나중에 검사하므로 본문이 최소 한 번은 실행된다.

let n = 10;

do {
  console.log("한 번은 실행된다");
} while (n < 5);
콘솔
  • 한 번은 실행된다

10 < 5는 거짓이지만 이미 본문을 지나온 뒤다. 쓸 일은 드물다.

break — 반복을 즉시 끝낸다

원하는 걸 찾으면 더 돌 이유가 없다.

const numbers = [3, 7, 12, 5, 20];

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] > 10) {
    console.log("10보다 큰 첫 값:", numbers[i]);
    break;
  }
  console.log("검사 중:", numbers[i]);
}
콘솔
  • 검사 중: 3
  • 검사 중: 7
  • 10보다 큰 첫 값: 12

12를 찾자마자 빠져나와서 520은 검사하지 않았다. 배열이 길수록 이득이 커진다.

5개짜리 배열에서 3번째에 답을 찾았다면
break 없음5회
break 있음3회

continue — 이번 회차만 건너뛴다

break가 반복을 끝낸다면, continue이번 회차만 포기하고 다음으로 넘어간다.

for (let i = 1; i <= 5; i++) {
  if (i % 2 === 0) continue;
  console.log(i);
}
콘솔
  • 1
  • 3
  • 5

짝수를 만나면 console.log를 건너뛴다. 5강에서 본 나머지 연산자 %가 여기서 쓰인다.

break 와 continue

break

반복문을 탈출

  • 다음 회차가 아예 없다
  • 반복문 뒤 코드로 이동
  • "찾았으니 그만"

continue

이번 회차만 건너뜀

  • 반복은 계속된다
  • 증감식으로 이동
  • "이건 넘어가고 다음"

배열을 도는 더 쉬운 방법

인덱스가 필요 없다면 for...of가 훨씬 읽기 좋다.

const fruits = ["사과", "바나나", "포도"];

for (const fruit of fruits) {
  console.log(fruit);
}
콘솔
  • 사과
  • 바나나
  • 포도

i도, length도, fruits[i]도 없다. 실수할 여지가 줄어든다.

정리하면

  • for(초기화; 조건; 증감) 세 자리로 이루어지고, 증감은 본문 뒤에 실행된다.
  • 배열을 돌 때는 i < arr.length라고 쓴다. <=를 쓰면 마지막에 undefined를 읽는다.
  • while은 조건을 거짓으로 만드는 코드를 본문에 직접 넣어야 한다. 없으면 무한 루프다.
  • break는 반복을 끝내고, continue는 이번 회차만 건너뛴다.
  • 인덱스가 필요 없다면 for...of가 더 안전하고 읽기 좋다.

Part 3이 끝났다. 다음 강의부터는 함수다. 지금까지 쓴 코드를 이름 붙여 묶고, 필요할 때 꺼내 쓰는 법을 배운다.

반복문 — 같은 일을 백 번 시킨다 — 디코드랩(DCODELAB)