드리프트 / Posts / 웹 개발 배우기 5편 - 자바스크립트 반복문, for와 while로 지루한 작업 자동화하기

Created Thu, 09 Oct 2025 10:00:00 +0900 Modified Fri, 17 Oct 2025 19:20:11 +0900

웹 개발 배우기 5편 - 자바스크립트 반복문, for와 while로 지루한 작업 자동화하기

코드를 짜다 보면 똑같은 작업을 수없이 반복해야 할 때가 있거든요.

이럴 때 우리를 구원해 줄 마법 같은 도구가 바로 ‘반복문’입니다.

오늘은 자바스크립트에서 반복 작업을 아주 우아하게 처리하는 법을 제대로 파헤쳐 볼 건데요.

기본부터 실전 프로젝트까지, 차근차근 따라오시면 어느새 반복문의 달인이 되어 있을 겁니다.

반복의 기본 전제 ‘순회 가능한 데이터’

자바스크립트에는 반복문이 순서대로 값을 꺼내올 수 있는, 소위 ‘순회 가능한(iterable)’ 데이터 타입들이 존재하는데요.

이런 데이터가 있어야 반복문이 제 역할을 할 수 있습니다.

대표적으로는 배열(Array)과 문자열(String)이 있는데요.

이들은 for...of 같은 반복문과 함께 쓰이거나, Array.from() 메서드를 통해 배열로 변환될 수 있습니다.

예를 들어, 문자열을 Array.from()에 넣으면 각 글자가 분리된 배열이 만들어지거든요.

Array.from('abc'); // 결과: [ 'a', 'b', 'c' ]

정말 간단하죠?

이제 이 순회 가능한 데이터를 가지고 본격적으로 반복문을 돌려보겠습니다.

가장 직관적인 반복문 for…of

요즘 자바스크립트에서 가장 사랑받는 반복문은 단연 for...of인데요.

코드 블록을 0번 혹은 그 이상, 특정 횟수만큼 실행시키는 역할을 합니다.

const arr = ['준비', '시작', '출발'];


for (const elem of arr) {
  console.log(elem);
}

위 코드를 보면 arr이라는 배열의 요소를 하나씩 순서대로 꺼내 elem이라는 변수에 담고, 중괄호 {} 안의 코드, 즉 ‘루프의 몸통(body)‘을 실행하는데요.

이 루프는 배열 arr의 모든 요소를 순회하게 됩니다.

먼저 arr[0]인 ‘준비’를 elem에 할당하고 몸통을 실행하고, 다음엔 arr[1]인 ‘시작’을 할당해서 실행하는 식이죠.

몸통이 한 번 실행되는 것을 ‘루프 이터레이션(loop iteration)‘이라고 부릅니다.

콘솔에는 아래와 같이 찍히게 될 거고요.

준비
시작
출발

for...of는 순회 가능한 모든 데이터에 쓸 수 있기 때문에 문자열에도 당연히 적용되는데요.

결과는 예상하시는 그대로입니다.

for (const ch of 'abc') {
  console.log(ch);
}
// 결과:
// a
// b
// c

인덱스와 값을 동시에 얻는 법

그런데 가끔은 배열의 값뿐만 아니라 그 값이 몇 번째에 있는지, 즉 ‘인덱스’ 정보도 함께 필요할 때가 있거든요.

그럴 땐 배열의 .entries() 메서드와 ‘구조 분해 할당(Destructuring)‘을 활용하면 됩니다.

const arr = ['준비', '시작', '출발'];

for (const [index, value] of arr.entries()) {
  console.log(index + '. ' + value);
}
// 결과:
// 0. 준비
// 1. 시작
// 2. 출발

조금 복잡해 보이지만, 하나씩 뜯어보면 정말 별거 아닌데요.

우선 .entries()는 배열의 각 요소를 [인덱스, 값] 형태의 쌍으로 묶어서 새로운 순회 가능한 데이터로 만들어주는 메서드입니다.

Array.from(['a', 'b'].entries());
// 결과: [ [ 0, 'a' ], [ 1, 'b' ] ]

그 다음 const [index, value] 부분이 바로 ‘배열 구조 분해 할당’인데요.

마치 상자를 열어서 내용물을 각각 다른 변수에 담는 것처럼, [0, 'a']와 같은 배열의 요소를 indexvalue 변수에 순서대로 쏙쏙 할당해주는 문법입니다.

덕분에 우리는 코드를 훨씬 깔끔하게 작성할 수 있거든요.

// 구조 분해 할당 사용
for (const [index, value] of ['네', '아니오', '아마도'].entries()) {
  console.log(index + '. ' + value);
}

// 구조 분해 할당 미사용
for (const pair of ['네', '아니오', '아마도'].entries()) {
  console.log(pair[0] + '. ' + pair[1]);
}

두 코드는 똑같이 동작하지만, 구조 분해 할당을 쓴 쪽이 훨씬 더 읽기 편하다는 걸 바로 알 수 있습니다.

개발자의 오랜 친구 클래식 for 루프

for...of가 편리하긴 하지만, 때로는 더 정밀한 제어가 필요한 순간이 있는데요.

이럴 때 바로 클래식 for 루프가 등장합니다.

C나 Java 같은 다른 언어에 익숙하시다면 아주 반가운 얼굴일 텐데요.

세미콜론으로 구분된 세 부분으로 구성됩니다.

for (초기화; 조건; 증감) 형태입니다.

for (let i = 0; i < 5; i++) {
  console.log('현재 숫자는 ' + i + '입니다.');
}
  1. let i = 0: 루프가 시작되기 전, 딱 한 번 실행되는 ‘초기화’ 부분입니다.

보통 카운터 변수를 만들죠.

  1. i < 5: 루프의 몸통이 실행되기 전에 매번 확인하는 ‘조건’ 부분인데요.

이 조건이 true여야만 루프가 계속됩니다.

  1. i++: 루프의 몸통이 한 번 실행된 후에 실행되는 ‘증감’ 부분입니다.

주로 카운터 변수를 1씩 증가시키죠.

이 루프는 i가 0부터 4까지 변하는 동안 총 5번 실행됩니다.

for...of와 달리 인덱스를 직접 제어할 수 있어서 배열을 거꾸로 순회하는 등의 작업도 가능합니다.

조건이 핵심인 while 루프

이번엔 while 루프를 만나볼 차례인데요.

이 친구는 반복 횟수가 정해져 있지 않고, 오직 ‘특정 조건이 참인 동안’ 계속해서 코드를 실행합니다.

let count = 0;

while (count < 3) {
  console.log('아직 괜찮아!');
  count++;
}

console.log('이제 그만!');

while 뒤의 괄호 안 조건 (count < 3)true인 동안 몸통 안의 코드가 반복적으로 실행되거든요.

여기서 아주 중요한 점은, 루프 몸통 안에서 언젠가는 조건을 false로 만드는 코드가 반드시 있어야 한다는 것입니다.

위 예제에서는 count++가 그 역할을 하죠.

만약 이 코드가 없다면 count는 영원히 0에 머물고, count < 3 조건은 항상 참이 되어 ‘무한 루프’에 빠지게 됩니다.

브라우저가 멈춰버리는 끔찍한 경험을 할 수 있으니 while문을 쓸 땐 항상 조심해야 합니다.

실전처럼 데이터 가공하기

반복문은 주로 데이터를 가공하는 데 쓰이는데요.

가장 흔한 패턴은 빈 배열을 하나 만들어두고, 반복문을 돌면서 조건에 맞는 값들만 골라 이 배열에 추가하는 방식입니다.

배열의 끝에 요소를 추가할 때는 .push() 메서드를 사용하는데요.

const arr = [];

arr.push('a');

// arr은 이제 ['a']
arr.push('b');

// arr은 이제 ['a', 'b']

이걸 활용해서 비어있지 않은 문자열만 골라내는 함수를 만들어 보겠습니다.

const extractNonEmptyStrings = (strs) => {
  const result = [];

  for (const str of strs) {
    if (str.length > 0) {
      result.push(str);
    }
  }
  return result;
};

extractNonEmptyStrings(['네', '', '아니오', '', '아마도']);
// 결과: [ '네', '아니오', '아마도' ]

아주 간단하지만 강력한 데이터 처리 로직이 완성되었습니다.

동적 HTML 생성을 위한 도구들

이제 배운 반복문을 활용해서 웹 페이지의 내용을 동적으로 만들어보는 프로젝트를 진행해 볼 건데요.

그 전에 몇 가지 유용한 도구를 먼저 익혀야 합니다.

1. 문자열과 숫자를 누적하는 += 연산자

+= 연산자는 기존 변수의 값에 새로운 값을 더해서 다시 할당하는 축약 표현인데요.

myVar = myVar + value;myVar += value;로 줄여 쓸 수 있습니다.

숫자 덧셈은 물론, 문자열을 이어 붙이는 데도 아주 유용하게 쓰입니다.

let str = '';

str += '아이스 ';
 // str은 '아이스 '

str += '크림';
   // str은 '아이스 크림'

2. 변수를 품는 문자열 ‘템플릿 리터럴’

따옴표(' 또는 ") 대신 백틱(`)으로 감싸 만드는 문자열을 ‘템플릿 리터럴’이라고 하는데요.

이 친구의 가장 큰 특징은 문자열 안에 변수나 표현식을 아주 쉽게 집어넣을 수 있다는 점입니다.

${...} 구문을 사용하면 되거든요.

const num = 99;

const message = `${num}개의 주스 병이 벽에`;

// message는 '99개의 주스 병이 벽에'

또한, 템플릿 리터럴은 여러 줄에 걸쳐 문자열을 작성할 수도 있어서 HTML 코드를 만들 때 정말 편리합니다.

프로젝트 좋아하는 과일 목록 만들기

이제 본격적으로 프로젝트를 진행해 보겠습니다.

먼저, 과일 목록이 HTML에 고정되어 있고, 사용자가 체크박스를 선택하면 선택된 과일 목록을 보여주는 간단한 웹 앱을 만들어 볼 건데요.

사용자가 체크박스를 클릭할 때마다 updateFeedback 함수가 호출됩니다.

const updateFeedback = () => {
  const selectedFruits = [];

  for (const i of document.querySelectorAll('input')) { // 모든 input 태그 선택
    if (i.checked) { // 체크된 상태인지 확인
      selectedFruits.push(i.value);
      // 체크된 과일의 값을 배열에 추가
    }
  }
  // 배열의 요소들을 ', '로 연결하여 화면에 표시
  document.querySelector('#feedbackSpan').innerText =
    selectedFruits.join(', ');
};

// <ul> 태그에서 'change' 이벤트가 발생할 때마다 updateFeedback 함수 실행
document.querySelector('ul').addEventListener('change', (event) => {
    updateFeedback();
});

document.querySelectorAll('input')은 페이지의 모든 <input> 요소를 가져오고, for...of 루프는 이 요소들을 하나씩 순회하는데요.

각 input 요소의 .checked 속성을 통해 선택 여부를 확인하고, 선택된 과일의 valueselectedFruits 배열에 push합니다.

마지막으로, 배열 메서드인 .join(', ')을 사용해서 배열의 모든 요소를 쉼표와 공백으로 연결한 뒤 화면에 보여주는 거죠.

프로젝트 업그레이드 동적으로 목록 생성하기

이번에는 한 단계 더 나아가 볼 건데요.

HTML에는 텅 빈 <ul> 태그만 두고, 자바스크립트 배열에 담긴 과일 목록을 사용해서 동적으로 체크박스를 생성해 보겠습니다.

const fruits = [
  '사과',
  '바나나',
  '오렌지',
  '딸기',
  '수박',
];

const ul = document.querySelector('ul');

for (const f of fruits) {
  const html = `
    <li>
      <label>
        <input type="checkbox" value="${f}"> ${f}
      </label>
    </li>
  `;
  ul.insertAdjacentHTML('beforeend', html);
}

fruits 배열을 for...of 루프로 순회하면서 각 과일에 대한 HTML 코드를 템플릿 리터럴로 생성하는데요.

그리고 .insertAdjacentHTML('beforeend', html) 메서드를 사용해서 생성된 HTML 코드를 <ul> 태그의 맨 끝 자식 요소로 계속해서 추가해줍니다.

이렇게 자바스크립트로 생성된 HTML을 ‘동적 HTML’이라고 부르는데요.

데이터만 바꾸면 화면이 알아서 바뀌기 때문에 훨씬 유연하고 강력한 웹 페이지를 만들 수 있습니다.

루프를 제어하는 특별한 키워드

때로는 루프가 끝까지 다 돌기 전에 멈추거나, 특정 조건에서 현재 순서를 건너뛰고 싶을 때가 있는데요.

이럴 때 breakcontinue 키워드를 사용합니다.

break: 루프를 즉시 중단하고 루프 다음 코드로 실행 흐름을 옮깁니다.

원하는 것을 찾았을 때 더 이상 불필요한 반복을 하지 않기 위해 사용되죠.

const firstStrStartingWithA = (strs) => {
  let result = undefined;

  for (const str of strs) {
    if (str.startsWith('A')) {
      result = str;
      break; // 'A'로 시작하는 첫 단어를 찾았으니 루프 종료!
    }
  }
  return result;
};

continue: 현재 이터레이션을 중단하고 즉시 다음 이터레이션으로 넘어갑니다.

특정 조건만 제외하고 로직을 실행하고 싶을 때 유용합니다.

for (let i = 0; i < 5; i++) {
  if (i === 2) {
    continue; // i가 2일 때는 console.log를 건너뛴다
  }
  console.log(i);
}
// 결과: 0, 1, 3, 4

그래서 어떤 반복문을 써야 할까

이제 다양한 반복문을 배웠으니, 상황에 맞게 최적의 무기를 선택할 수 있어야 하는데요.

간단한 가이드를 드리겠습니다.

for...of: 배열이나 문자열 등 순회 가능한 데이터의 ‘값’을 순서대로 사용하는 가장 일반적이고 추천되는 방법입니다.

클래식 for: 인덱스를 직접 제어해야 할 때(예: 배열 거꾸로 순회하기)나, 반복 횟수에 대한 정밀한 조건이 필요할 때 사용합니다.

while: 반복 횟수가 명확하지 않고, 특정 조건이 만족되는 동안 계속 실행해야 할 때 적합합니다.

단, 무한 루프의 위험을 항상 염두에 두어야 합니다.

for...in: 객체(Object)의 속성(key)들을 순회하기 위해 사용되는데요.

배열에 사용하는 것은 권장되지 않으며, 순서가 보장되지 않는 특징이 있습니다.

마무리하며

오늘은 자바스크립트의 핵심 근육이라고 할 수 있는 반복문에 대해 깊이 있게 알아봤는데요.

단순히 코드를 반복 실행하는 것에서 시작해, 데이터를 가공하고 동적으로 웹 페이지를 그리는 실전 예제까지 함께했습니다.

for...of, for, while 각각의 특징과 쓰임새를 잘 이해하고, breakcontinue로 흐름을 제어할 수 있다면 이제 여러분의 코드는 훨씬 더 효율적이고 유연해질 겁니다.

코딩은 결국 반복과의 싸움이거든요.