본문 바로가기
Javascript study

[Javascript] while과 for 반복문

by 카누가 좋아요 2023. 7. 14.

📌 참고 사이트

while과 for 반복문 (javascript.info)

 

while과 for 반복문

 

ko.javascript.info

 

 

 

📋 반복문

반복문(loop)를 사용하면 동일한 코드를 여러 번 반복할 수 있다

ex) 상품 목록에서 상품을 차례대로 출력해야 하는 경우, 숫자를 1부터 10까지 하나씩 증가시키면서 동일한 코드를 반복 실행하는 경우 등

 

 

 

📋 while 반복문

📍 문법

 

while (condition) {
    // 코드
    // '반복문 본문(body)' 라고 불림
}

 

➡️ 조건(condition)이 이면 반복문 본문의 코드 부분이 실행된다.

➡️ 반복문 조건에는 비교 뿐만 아니라 모든 종류의 표현식, 변수가 올 수 있다. 조건은 while에 의해 평가되고, 평가 후에는 불린값으로 변경된다.

➡️ 반복문의 본문이 한 번 실행되는 것을 반복(iteration, 이터레이션)이라고 부른다. 

➡️ 본문 코드에서 조건에 존재하는 변수를 조작해 줌으로써 반복문을 멈추게 할 수 있다.

 

 

📍 while문 예시

<ex 1>

let i = 0;
while (i < 3) {     
    alert(i);     // 0, 1, 2
    i++;     // 후에 i는 1 증가
}

 

위 코드에서 i++가 존재하지 않으면 i는 계속 0이 되어 i < 3이 계속 true가 되므로 이론적으로 반복문이 무한 반복된다.

 

<ex 2>

let i = 3;
while (i) {     // i가 0이 되면 조건이 거짓이 되어 반복문이 멈춘다.
    alert(i);
    i--;     // 이후에 i가 1 감소
}

 

 

 

📋 do ... while 반복문

📍 문법

 

do {
    // 반복문 본문
} while (condition);

 

➡️ 본문이 먼저 한 번 실행되고, 조건을 확인 후 조건이 true일 동안에만 본문이 계속 실행된다.

(본문이 먼저 한 번 실행되는 점만 제외하면 일반 반복문과 작동 과정이 같다.)

➡️ 따라서 do ... while문은 조건이 true인지 아닌지에 상관 없이 본문을 최소한 한 번이라도 실행하고 싶을 때사용해야 한다. (대다수의 상황에서는 그냥 while문이 적합하다.)

 

 

📍 do ... while문 예시

 

let i = 0;
do {     // 일단 무조건 i(0)을 알림창에 한 번 띄우고, i를 1 증가시킨다.
    alert(i);   
    i++
} while (i < 3);     // 그러고 나서 i가 3보다 작을 때까지만 위 본문을 반복한다.
// 결국 화면에는 0과 1과 2만 출력된다.

 

 

 

📋 for 반복문

📍 문법

 

for (begin ; condition ; step) {
    // ... 반복문 본문 ...
}

 

➡️ begin : 반복문에 진입할 때 단 한 번 실행된다. (주로 카운터 변수 정의)

➡️ condition : 반복마다 해당 조건이 확인된다. false가 될 경우 반복문이 종료된다. (주로 변수의 범위)

➡️ body : 조건(condition)이 일 동안 계속해서 실행된다.

➡️ step : 각 반복에서 본문(body)이 실행된 이후에 실행된다. (주로 변수의 증가 or 감소)

 

 

📍 for문 예시

 

for (let i = 0; i < 3; i++) {    
    alert(i);     // 결과적으로 0, 1, 2가 알림창에 출력됨.
}

 

➡️ begin은 let i = 0, condition은 i < 3, body는 alert(i), step은 i++에 해당된다.

1️⃣ 변수 i 정의 (let i  = 0) → 조건 확인 (i(0) < 3 true) → 본문 실행 (alert(0)) → 변수 i값 1 증가 (i++, 반환되는 값은 현재 i값 0이고, 1 증가는 반환 후에 이루어짐.)

2️⃣ 조건 확인 (i(1) < 3 true) → 본문 실행 (alert(1))  → 변수 i 값 1 증가 (i++)

3️⃣ 조건 확인 (i(2) < 3 true) → 본문 실행 (alert(2)) → 변수 i 값 1 증가 (i++)

4️⃣ 조건 확인 (i(3) < 3 false) → 반복문 종료

 

❗ 인라인 변수 선언

위 예시에서 카운터 변수 i를 반복문 안에서 선언하였다. 이러한 방식을 인라인 변수 선언이라고 부른다.

인라인 변수 선언 방식으로 선언된 변수는 반복문 안에서만 접근할 수 있다.

물론 반복문 밖에서 정의된 변수를 사용하는 것도 가능하다.

 

 

📍 구성 요소 생략하기

➡️ 반복문이 시작될 때 아무것도 할 필요가 없으면 begin을 생략하는 것이 가능하다.

 

let i = 0;     // i를 선언하고 값도 할당했다.

for (; i < 3 ; i++) {     // 위에서 i를 선언했으므로 begin이 필요하지 않기 때문에 생략하엿다.
    alert(i);     // 0, 1, 2
}

 

➡️ step 부분 또한 생략이 가능하다.

 

let i = 0;

// 위에서 선언한 i 이용
for (; i < 3;) {     // step 생략
    alert(i++);     // step 부분에 작성할 것을 본문에 작성해 주었다.
}

 

위 예시의 경우 while (i < 3)과 동일해진다.

 

➡️ 모든 구성 요소를 생략할 경우, 무한 반복문이 만들어진다.

 

for (;;) {
    // 끊임 없이 본문 실행
}

 

 

 

📋 반복문 빠져나오기

➡️ 보통의 경우 반복문의 조건(condition)이 false가 되면 반복문이 종료된다.

 

➡️ break를 사용하여 원하는 때에 반복문을 빠져나오게 할 수도 있다.

 

let sum = 0;

while (true) {
    let value = +prompt("숫자를 입력하세요.", '');
    if (!value) break;
    sum += value;
}

alert('합계: ' + sum);

 

사용자가 입력한 값을 + 연산자 (단항 연산자)를 통해 숫자로 변환하고 있고, 그것을 value에 할당한다.

그 후 value를 불린형으로 하였을 때 false이면(숫자가 아닐 경우 or 0을 입력한 경우 or 취소를 누른 경우) break가 실행되어 반복문이 종료되고 합계가 출력되게 한다.

(!value가 true가 되면 break가 실행된다. 따라서 break가 실행되는 경우는 value가 false인 경우이다.)

만약 !value에서 false가 된다면 (0이 아닌 숫자를 입력하고 확인을 누른 경우) break가 실행되지 않고 sum += value가 실행된다.

이 과정이 !value가 true가 되어 break가 실행되기 전까지 계속 진행된다.

 

➡️ 반복문의 시작 지점이나 끝 지점에서 조건을 확인하는 것이 아니라 본문 가운데 혹은 본문 여러 곳에서 조건을 확인해야 하는 경우 위와 같이 무한 반복문 + break 조합을 사용하면 좋다. 

 

➡️ 삼항 연산자(?)에서는 break를 사용할 수 없다. (에러 발생)

 

 

 

📋 continue (다음 반복으로 넘어가기)

➡️ continue전체 반복문을 멈추지 않고 현재 실행 중인 이터레이션(반복)을 멈추고 반복문이 다음 이터레이션을 강제로 실행시키도록 한다. (조건 통과 시)

즉, 현재 반복을 종료시키고 다음 반복으로 넘어가고 싶을 때 사용할 수 있다.

 

<ex>

for (let i = 0 ; i < 10 ; i++) {
    // 아래 조건이 참이라면(i가 짝수라면) 남아있는 본문(alert문)은 실행되지 않고 다시 윗줄로 돌아감.
    if (i % 2 == 0) continue;
    alert(i);     // 1, 3, 5, 7, 9가 차례로 출력됨.
}

 

➡️ continue중첩을 줄이는 데 도움을 준다.

continue를 사용하지 않고 코드를 작성하려면 다음과 같이 작성해야 한다.

 

for (let i = 0 ; i < 10 ; i++) {
    if (i % 2) {
        alert(i);
    }
}

 

continue를 사용하는 대신에 if 블록으로 감쌌는데, 이렇게 작성하면 중첩 레벨이 하나 더 늘어나 전체적으로 가독성이 떨어질 수 있다.

 

➡️ 삼항 연산자(?)에서 continue를 사용할 수 없다. (에러 발생)

 

 

 

📋 break / continue 와 레이블

여러 개의 중첩 반복문을 한 번에 빠져나와야 하는 경우를 살펴보자.

아래 예시는 i와 j를 반복하며 프롬프트 창에 (0, 0)부터 (2, 2)까지의 좌표 (i, j)를 입력받게 해주는 코드이다.

만약 사용자가 취소 버튼을 눌러서 반복문을 빠져나와야 하는 경우에는 어떻게 해야 할까?

 

for (let i = 0 ; i < 3 ; i++) {     // i : x좌표
    for (let j = 0 ; j < 3 ; j++) {     // j : y좌표
        let input = prompt(`(${i}, ${j})의 값`, '');     // 입력받기
        // 이 부분에서 멈춰야 한다.
    }
}

alert('완료!');

 

input 부분 아래에 break를 작성하면 안쪽에 있는 반복문(j에 대한 for문)만 빠져나올 수 있다. 따라서 i가 1 증가되고 j에 대한 반복문이 다시 실행될 수 있다.

겉에 있는 반복문(i에 대한 for문)까지 빠져나올 수 있게 하기 위해서는 레이블(label)을 사용하면 된다.

 

 

📍 레이블 (label)

➡️ 반복문 앞에서 콜론과 함께 쓰이는 식별자이다.

➡️ 반복문 안에서 break labelName의 형태로 사용하면 레이블에 해당하는 반복문을 빠져나오는 것이 가능하다.

 

outer: for (let i = 0 ; i < 3 ; i++) {     // outer가 레이블명, 반복문 앞에 콜론(:)과 함께 쓰임. 이로써 이중 반복문이 하나의 레이블이 됨.
    for (let j = 0 ; j < 3 ; j++) {
        let input = prompt(`(${i}, ${j})의 값`, '');
        // 사용자가 아무것도 입력하지 않거나('') cancel을 누르면 중첩 반복문 모두를 빠져나가게 된다.
        if (!input) break outer;     // break 옆에 레이블명인 outer를 적어주었다.
    }
}

alert('완료!');

 

위 예시에서 break outer는 outer라는 레이블이 붙은 반복문을 찾고, 해당 반복문을 빠져나오게 된다.

반복문을 빠져나온 이후는 반복문 밖에 있는 코드를 차례로 실행한다.

 

➡️ continue 지시자를 레이블과 함께 사용하면 레이블이 붙은 반복문의 다음 이터레이션이 실행된다.

 

let i, j;

loop1:     
for (i = 0; i < 3; i++) {      // 첫 번째 for 문은 "loop1"로 레이블이 지정됩니다.
  loop2:
  for (j = 0; j < 3; j++) {   // 두 번째 for 문은 "loop2"로 레이블이 지정됩니다.
    if (i === 1 && j === 1) {
      continue loop1;     // i가 1이면서 j가 1일 경우 loop1에서(i에 대한 for문)의 다음 이터레이션(i가 2일 때로)이 실행된다.
    }
    console.log(`i = ${i}, j = ${j}`);
  }
}

// Logs:
// i = 0, j = 0
// i = 0, j = 1
// i = 0, j = 2
// i = 1, j = 0
// i = 2, j = 0
// i = 2, j = 1
// i = 2, j = 2

* 코드 출처: JavaScript - label - 자바스크립트에는 레이블과 관련된 몇 가지 문제가 있으며,특히 다른 브라우저와의 호환성 문제가 가장 심각합니다. (runebook.dev)

 

➡️ 레이블을 사용한다고 해서 정말 아무 반복문으로 점프하는 것은 불가능하다.

breakcontinue 지시자는 반복문 안에서만 사용할 수 있고, 레이블은 반드시 break나 continue 지시자 위에 위치해야 한다.

 

 

 

✏️ 과제

📍 반복문의 마지막 값

아래 코드를 실행했을 때 alert 창에 마지막으로 뜨는 값은 무엇일까?

 

let i = 3;

while (i) {
    alert(i--);
}

 

🅰️

답은 1이다.

i--에 사용된 --는 후위 연산자이다. 따라서 alert의 인자로 들어가는 반환값은 기존의 값이고 1 감소는 반환 후에 이루어지게 된다.

차례대로 나타내면 alert(3), alert(2), alert(1)이 실행되게 된다. 

alert(1) 실행 후 i의 값은 0이 되고, 그러면 while (0)과 마찬가지의 상황이 되어 조건문이 false가 되므로 반복문이 종료되게 된다. 따라서 1 출력이 마지막이다.

 

 

📍 while 반복문의 출력값 예상하기

while 반복문이 순차적으로 실행될 때마다 alert 창에 어떤 값이 출력될지 예상해보자.

아래 두 예시는 같은 값을 출력할까?

 

1. 전위형 증가 연산자를 사용한 경우 (++i)

 

let i = 0;
while (++i < 5) alert(i);

 

2. 후위형 증가 연산자를 사용한 경우 (i++)

 

let i = 0;
while (i++ < 5) alert(i);

 

🅰️ 

답은 완전히 동일한 값을 출력하지는 않는다 이다.

 

1️⃣ ++i 에는 전위 연산자 ++가 사용되었으므로 반환값은 기존 값 + 1의 값이 된다.

따라서 alert(1), alert(2), alert(3), alert(4) 가 차례로 실행되고 그 다음의 i++값으로 5가 반환되므로 반복문이 종료된다.

결론적으로 1, 2, 3, 4가 차례로 알림창에 출력되게 된다.

 

2️⃣ i++에는 후위 연산자 ++가 사용되었으므로 반환 값은 기존 값이 되고, 반환 이후 값이 1 증가하게 된다.

따라서 alert(1), alert(2), alert(3), alert(4), alert(5)까지 차례로 실행되게 된다. alert 문으로 들어가는 인자 i의 값은 ++i에서 반환되는 값보다 항상 1이 크기 때문이다.

결론적으로 1, 2, 3, 4, 5가 차례로 알림창에 출력되게 된다.

 

 

📍 for 반복문의 출력값 예상하기

for 반복문이 순차적으로 실행될 때마다 alert 창에 어떤 값이 출력될지 예상해 보자.

아래 두 예시는 같은 값을 출력할까?

 

1. 후위형 증가 연산자를 사용한 경우 (i++)

 

for (let i = 0 ; i < 5 ; i++) alert(i);

 

2. 전위형 증가 연산자를 사용한 경우 (++i)

 

for (let i = 0 ; i < 5 ; ++i) alert(i);

 

🅰️

답은 두 경우 모두 동일하다.

for 문에서 모든 작업이 시작되기 전 let i = 0;이 먼저 실행된다.

그리고 i < 5의 조건이 true가 되는지 확인하고 alert문을 실행한다. i = 0이었으므로 0부터 출력된다.

그리고 나서 i++와 ++i가 실행된다. but 위에서는 i++과 ++i의 반환값을 사용하는 것이 아니고 1이 증가된 값을 사용하는 것이다. 그러므로 차이가 없다.

위 과정이 i < 5가 false가 될 때까지 반복되고, false가 되면 반복문이 종료된다.

결론적으로 두 경우 모두 0부터 4까지 알림창에 숫자가 출력되게 된다.

 

 

📍 for 반복문을 이용해 짝수 출력하기

for 반복문을 이용하여 2부터 10까지 숫자 중 짝수만을 출력해라.

 

🅰️

 

// continue를 이용하여 코드 작성하기
for (let i = 2 ; i <= 10 ; i++) {
    if (i % 2 === 1) continue;     // i가 홀수일 경우 다음 이터레이션(반복)으로 넘어감.
    console.log(i);     // i가 홀수가 아닐 경우 옆 console.log가 실행됨.
}

// break를 이용하여 코드 작성하기
for (let i = 2 ; i <= 10 ; i++) {
    if (i % 2 === 0) {     // i가 짝수일 경우에만 i가 출력됨.
        console.log(i);
    }
}

 

 

📍 for 반복문을 while 반복문으로 바꾸기

for 반복문을 while 반복문으로 바꾸되, 동작 방식과 출력 결과가 동일하게 해보자.

 

for (let i = 0; i < 3 ; i++) {
    alert(`number ${i}!`);
}

 

🅰️

 

let i = 0;

while (i < 3) {
    alert(`number ${i}!`);
    i++;
}

 

 

📍 사용자가 유효한 값을 입력할 때까지 프롬프트 창 띄우기

사용자가 100보다 큰 숫자를 입력하도록 안내하는 프롬프트 창을 띄워보자. 사용자가 조건에 맞지 않은 값을 입력한 경우 반복문을 사용해 동일한 프롬프트 창을 띄워주자.

사용자가 100을 초과하는 숫자를 입력하거나 취소 버튼을 누른 경우, 혹은 아무것도 입력하지 않고 확인 버튼을 누른 경우에는 더는 프롬프트 창을 띄워주지 않아도 된다.

사용자가 오직 숫자만 입력한다고 가정하고 답안을 작성하도록 해 보자. 숫자가 아닌 값이 입력되는 예외 상황은 처리하지 않아도 된다.

 

나의 🅰️

 

do {
  var userInput = prompt('100보다 큰 숫자를 입력하세요.', '');
} while (+userInput <= 100 && userInput !== null && userInput !== '');

 

정답 🅰️

 

let num;     // num은 let 예약어로 반복문 밖에서 미리 선언해 줌.

do {
  num = prompt("100을 초과하는 숫자를 입력해 주세요.", 0); 
} while (num <= 100 && num);     // num이 100보다 작거나 같은 경우나 값 자체가 true인 경우 중 하나라도 거짓이 되면 반복문 종료

 

➡️ 일단 처음 한 번은 무조건 입력받아야 하기 때문에 do ... while문을 사용하였다.

➡️ 반복문이 멈춰야 할 때는 100 초과 숫자를 입력받았거나(num > 100), 취소 버튼을 눌렀거나(null 반환), 아무것도 입력하지 않고 제출(위에서는 초기값을 0으로 설정해 주었으므로 0 반환, 만약 초기값 설정이 없으면 빈 문자열 '' 반환)했을 때이다. 

위에서 작성한 반복문의 조건문을 살펴보자.

→ num <= 100 : 문제 조건에 맞지 않는 100 이하의 수를 의미한다. num에는 string형의 값이 담겨있지만 숫자 100하고 비교하므로 num이 숫자로 자동 형변환 된다. (100 초과 수를 입력했을 경우 false)

→ num : 숫자를 불리언형으로 형변환 하였을 때의 값을 사용한다. (null이나 0이 들어가면 num <= 100에서는true이지만 num에서는 false가 됨.)

둘 중 하나라도 false가 되면 반복문이 멈추게 된다.

➡️ 둘 다 true가 되면 100 초과 숫자를 입력받거나, 취소 버튼이 눌리거나, 아무것도 입력이 안 될 때까지 프롬프트가 다시 띄워지게 된다.

 

 

📍 소수(prime number) 출력하기

2부터 n까지의 숫자 중 소수만 출력해주는 코드를 작성해 보자.

(작성한 코드는 임의의 숫자 n에 대해 동작해야 한다.)

 

💻 break를 사용한 코드

 

let n = +prompt('1보다 큰 자연수를 입력해 주세요.', 2);     // 수를 입력받고 숫자형으로 형변환, n에 할당

for (let i = 2; i <= n; i++) {
  let flag = 1;     // 소수인지 아닌지를 나타내어주는 플래그 변수
  for (let j = 2; j < i; j++) {
    if (i % j === 0) {     
      flag = 0;     // i가 j로 나누어 떨어질 경우 소수가 아니므로 flag 변수에 0 저장
      break;
    }
  }
  if (flag) alert(i);     // flag 변수가 1일 때만 (true일 때만) i 출력
}

 

💻 레이블과 continue를 사용한 코드

 

let n = +prompt('1보다 큰 자연수를 입력해 주세요.', 2);

nextPrime: for (let i = 2; i <= n; i++) {
  // 2 이상 n 이하의 수인 n에 대한 반복문을 돌림
  for (let j = 2; j < i; j++) {
    // i를 나눌 수인 j에 대한 반복문을 돌림
    if (i % j === 0) continue nextPrime; // 소수가 아인 경우 다음 i로 넘어감.
  }
  alert(i); // 소수 출력
}

 

위에서 continue 지시자와 레이블을 함께 사용하면 레이블이 붙은 반복문의 다음 반복이 실행된다고 배웠다.

(break와 레이블을 함께 사용할 경우 다음 반복이 실행되는 것이 아니라 아예 중첩 반복문 자체를 빠져나오게 되기 때문에 우리가 원하는 결과를 얻을 수 없다.)

 

💡 j를 2와 i의 제곱근(i ** 0.5) 사이에서 찾는 것으로 바꾸면 좀 더 코드 최적화가 가능하다. 약수는 항상 짝지어서 존재하기 때문에 제곱근까지만 제수가 될 수 있는지 확인하면 그 뒤의 숫자들은 확인하지 않아도 소수 판별이 가능하다. 

'Javascript study' 카테고리의 다른 글

[Javascript] 함수  (0) 2023.07.17
[Javascript] switch문  (0) 2023.07.14
[Javascript] nullish 병합 연산자 '??'  (0) 2023.07.12
[Javascript] 논리 연산자  (0) 2023.07.10
[Javascript] if와 '?'를 사용한 조건 처리  (0) 2023.07.09

댓글