제어문

제어문

모던 자바스크립트 Deep Dive: 자바스크립트의 기본 개념과 동작 원리 - 08장 제어문

제어문(control flow statement) 은 조건에 따라 코드 블록을 실행(조건문)하거나 반복 실행(반복문)할 때 사용한다.

일반적으로 코드는 위에서 아래 방향으로 순차적으로 실행되는데 제어문을 사용하면 코드의 실행 흐름을 인위적으로 제어할 수 있다.

1. 블록문

블록문(block statement/compound statement) 은 0개 이상의 문을 중괄호로 묶은 것으로, 코드 블록 또는 블록이라고 부른다.

자바스크립트는 블록문을 하나의 실행 단위로 취급한다. 블록문은 단독으로 사용할 수도 있으나 일반적으로 제어문이나 함수를 정의할 때 사용하는 것이 일반적이다.

  • 블록문은 언제나 문의 종료를 의미하는 자체 종결성을 갖기 때문에 블록문의 끝에는 세미콜론을 붙이지 않는다
// 블록문
{
  var foo = 10;
}

// 제어문
var x = 1;
if (x < 10) {
  x++;
}

// 함수 선언문
function sum(a, b) {
  return a + b;
}

2. 조건문

조건문(conditional statement) 은 주어진 조건식(conditional exporeesion) 의 평가 결과에 따라 코드 블록(블록문)의 실행을 결정한다.

자바스크립트는

  • if ...else
  • switch

두 가지 조건문을 제공한다.

if …else 문

if ...else 문은 주어진 조건식(불리언 값으로 평가될 수 있는 표현식)의 평가 결과, 즉 논리적 참 또는 거짓에 따라 실행한 코드 블록을 결정한다.

if 문의 조건식이 불리언 값이 아닌 값으로 평가되면 자바스크립트 엔진에 의해 암묵적으로 불리언 값으로 강제 변환되어 실행할 코드 블록을 결정한다.

if(조건식) {
  // 조건식이 참이면 이 코드 블록을 실행한다.
} else {
  // 조건식이 거짓이면 이 코드 블록을 실행한다.
}
var num = 2;
var kind;

// if 문
if (num > 0) {
  kind = '양수'; // 음수를 구별할 수 없다
}
console.log(kind); // 양수

// if...else 문
if (num > 0) {
  kind = '양수';
} else {
  kind = '음수'; // 0은 음수가 아니다.
}
console.log(kind); // 양수

// if...else if 문
if (num > 0) {
  kind = '양수';
} else if (num < 0) {
  kind = '음수';
} else {
  kind = '';
}
console.log(kind); // 양수

코드 블록 내의 문이 하나뿐이라면 중괄호를 생략할 수 있다.

  • 대부분의 if ..else 문은 삼항 조건 연산자로 바꿔 쓸 수 있다.

삼항 조건 연산자는 값으로 평가되는 표현식을 만든다. 따라서 삼항 조건 연산자 표현식은 값처럼 사용할 수 있기 때문에 변수에 할당할 수 있다. 하지만 if ...else 문은 표현식이 아닌 문이다. 따라서 if ...else 문은 값처럼 사용할 수 없기 때문에 변수에 할당할 수 없다.

switch

switch 문은 주어진 표현식을 평가하여 그 값과 일치하는 표현식을 갖는 case 문으로 실행 흐름을 옮긴다.

case 문은 상항(case)을 의미하는 표현식을 지정하고 콜론으로 마친다. 그리고 그 뒤에 실행할 문들을 위치시킨다.

switch 문의 표현식과 일치하는 case 문이 없다면 실행 순서는 default 문으로 이동한다. default 문은 선택사항으로, 사용할 수도 있고 사용하지 않을 수도 있다.

switch (표현식) {
  case 표현식1:
    // switch 문의 표현식과 표현식1이 일치하면 실행될 문;
    break;
  case 표현식2:
    // switch 문의 표현식과 표현식2이 일치하면 실행될 문;
    break;
  default:
    // switch 문의 표현식과 일치하는 case 문이 없을 때 실행될 문;
}

switch 문은 논리적 참, 거짓보다는 다양한 사항(case)에 따라 실행할 코드 블록을 결정할 때 사용한다.

// 월을 영어로 변환한다. (11 → 'November')
var month = 11;
var monthName;

switch (month) {
  case 1: monthName = 'January';
    break;
  case 2: monthName = 'February';
    break;
  case 3: monthName = 'March';
    break;
  case 4: monthName = 'April';
    break;
  case 5: monthName = 'May';
    break;
  case 6: monthName = 'June';
    break;
  case 7: monthName = 'July';
    break;
  case 8: monthName = 'August';
    break;
  case 9: monthName = 'September';
    break;
  case 10: monthName = 'October';
    break;
  case 11: monthName = 'November';
    break;
  case 12: monthName = 'December';
    break;
  default: monthName = 'Invalid month';
}

console.log(monthName); // November

폴스루(fall through)
문을 실행할 후 switch 문을 탈출하지 않고 switch 문이 끝날 때까지 이후의 모든 case 문과 defalut 문을 실행하는 것.

break 키워드로 구성된 break 문은 코드 블록에서 탈출하는 역할을 한다.

default 문은 switch 문의 맨 마지막에 위치하므로 defalut 문의 실행이 종료되면 switch 문을 빠져나간다.

일부러 폴스루를 할용하는 경우도 있다.

var year = 2000; // 2000년은 윤년으로 2월이 29일이다.
var month = 2;
var days = 0;

switch (month) {
  case 1: case 3: case 5: case 7: case 8: case 10: case 12:
    days = 31;
    break;
  case 4: case 6: case 9: case 11:
    days = 30;
    break;
  case 2:
    // 윤년 계산 알고리즘
    // 1. 연도가 4로 나누어떨어지는 해(2000, 2004, 2008, 2012, 2016, 2020...)는 윤년이다.
    // 2. 연도가 4로 나누어떨어지더라도 연도가 100으로 나누어떨어지는 해(2000, 2100, 2200...)는 평년이다.
    // 3. 연도가 400으로 나누어떨어지는 해(2000, 2400, 2800...)는 윤년이다.
    days = ((year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0)) ? 29 : 28;
    break;
  default:
    console.log('Invalid month');
}

console.log(days); // 29

3. 반복문

반복문(loop statement) 은 조건식의 평가 결과가 참인 경우 코드 블록을 실행한다. 그 후 조건식을 다시 평가하여 여전히 참인 경우 코드 블록을 다시 실행한다. 이는 조건식이 거짓일 때까지 반복한다.

자바스크립트는

  • for
  • while
  • do ...while

의 반복문을 제공한다.

for 문

for 문은 조건식이 거짓으로 평가될 때까지 코드 블록을 반복 실행한다.

for (변수 선언문 떠는 할당문; 조건식; 증감식) {
    조건식이 참인 경우 반복 실행될 
}
  • for
    for (var i = 0; i < 2; i++) {
    console.log(i);
    }
    

for 문

for문을 실행하면 맨 먼저 변수 선언문 var i = 0이 실행된다. 변수 선언문은 단 한번만 실행된다.

조건식이 실행된다. 현재 i변수의 값은 0이므로 조건식의 평가 결과는 true이다.

조건식의 평가 결과가 true이므로 코드 블록이 실행된다.

코드 블록의 실행이 종료되면 증감식 i++가 실행되어 변수의 값은 1이 된다.

다시 조건식이 실행된다. 현재 i변수의 값은 1이므로 조건식의 평가 결과는 true이다.

조건식의 평가 결과가 true이므로 코드 블록이 다시 실행된다.

코드 블록의 실행이 종료되면 증감식 i++가 실행되어 변수의 값은 2가 된다.

다시 조건식이 실행된다. 현재 i변수의 값은 2이므로 조건식의 평가 결과는 false이다. 조건식의 결과가 false가 되면서 for 문의 실행이 종료된다.

  • for 문의 변수 선언문, 조건식, 증감식은 모두 옵션이다.
  • 하지만 어떤 식도 선언하지 않으면 무한루프가 된다.

무한 루프
코드 블록을 무한히 반복 실행하는 문이다.

  • for 문 내에 for 문을 중첩해 사용할 수 있다. 이를 중첩 for 문이라 한다.
for (var i = 1; i <= 6; i++) {
  for (var j = 1; j <= 6; j++) {
    if (i + j === 6) console.log(`[${i}, ${j}]`);
  }
}

// [1, 5]
// [2, 4]
// [3, 3]
// [4, 2]
// [5, 1]

while 문

while 문은 주어진 조건식의 평가 결과가 참이면 코드 블록을 계속해서 반복 실행한다. for 문은 반복 횟수가 명확할 때 주로 사용하고 while 문은 반복 횟수가 불명확할 때 주로 사용한다.

var count = 0;

// count가 3보다 작을 때까지 코드 블록을 계속 반복 실행한다.
while (count < 3) {
  console.log(count); // 0 1 2
  count++;
}
  • 조건식의 평가 결과가 참이면 무한루프가 된다.

    // 무한루프
    while (true) { ... }
    
  • 무한루프에서 탈출하기 위해서는 break 문으로 코드 블록을 탈출한다.

    var count = 0;
    // 무한루프
    while (true) {
      console.log(count);
      count++;
      // count가 3이면 코드 블록을 탈출한다.
      if (count === 3) break;
    } // 0 1 2
    


do …while 문

do ...while 문은 코드 블록을 먼저 실행하고 조건식을 평가한다. 따라서 코드 블록은 무조건 한 번 이상 실행된다.

var count = 0;

// 무한루프
var count = 0;

// count가 3보다 작을 때까지 코드 블록을 계속 반복 실행한다.
do {
  console.log(count);
  count++;
} while (count < 3); // 0 1 2

4. break 문

switch 문과 while 문에서 살펴보았듯이 break 문은 코드 블록을 탈출한다. 좀 더 정확히 표현하자면 코드 블록을 탈출하는 것이 아니라 레이블 문, 반복문(for, for...in, for...of, while, do...while) 또는 switch 문의 코드 블록을 탈출한다.

  • 레이블 문, 반복문, switch 문의 코드 블록 외에 break 문을 사용하려면 SyntaxError(문법 에러)가 발생한다.

    if (true) {
    break; // Uncaught SyntaxError: Illegal break statement
    }
    

레이블 문(label statement)

식별자가 붙은 문

// foo라는 레이블 식별자가 붙은 레이블 문
foo: console.log('foo');

switch 문의 case 문과 default 문도 레이블 문이다.

  • 레이블 문을 탈출하려면 break 문에 레이블 식별자를 지정한다.
    // foo라는 식별자가 붙은 레이블 블록문
    foo: {
      console.log(1);
      break foo; // foo 레이블 블록문을 탈출한다.
      console.log(2);
    }
    
    console.log('Done!');
    
  • 중첩된 for문의 내부 for문에서 break문을 실행하면 내부 for문을 탈출하여 외부 for문으로 진입한다. 이때 외부 for문을 탈출하려면 레이블 문을 사용한다.
    // outer라는 식별자가 붙은 레이블 for 문
    outer: for (var i = 0; i < 3; i++) {
      for (var j = 0; j < 3; j++) {
        // i + j === 3이면 outer라는 식별자가 붙은 레이블 for 문을 탈출한다.
        if (i + j === 3) break outer;
        console.log(`inner [${i}, ${j}]`);
      }
    }
    
    console.log('Done!');
    

    레이블 문은 중첩된 for문 외부로 탈출할 때 유용하지만 그 밖에 경우에는 일반적으로 권장하지 않는다.

    레이블 문을 사용하면 프로그램의 흐름이 복잡해져서 가독성이 나빠지고 오류를 발생시킬 가능성이 높아지기 때문이다.

  • break 문은 레이블 문뿐 아니라 반복문, switch 문에서도 사용할 수 있다.

    var string = 'Hello World.';
    var search = 'l';
    var index;
    
    // 문자열은 유사배열이므로 for 문으로 순회할 수 있다.
    for (var i = 0; i < string.length; i++) {
      // 문자열의 개별 문자가 'l'이면
      if (string[i] === search) {
        index = i;
        break; // 반복문을 탈출한다.
      }
    }
    
    console.log(index); // 2
    
    // 참고로 String.prototype.indexOf 메서드를 사용해도 같은 동작을 한다.
    console.log(string.indexOf(search)); // 2
    

5. continue 문

continue문은 반복문의 코드 블록 실행을 현 지점에서 중단하고 반복문의 증감식으로 실행 흐름을 이동시킨다.

  • break문 처럼 반복문을 탈출하지는 않는다.

    // continue 문을 사용하지 않으면 if 문 내에 코드를 작성해야 한다.
    for (var i = 0; i < string.length; i++) {
      // 'l'이면 카운트를 증가시킨다.
      if (string[i] === search) {
        count++;
        // code
      }
    }
    
    // continue 문을 사용하면 if 문 밖에 코드를 작성할 수 있다.
    for (var i = 0; i < string.length; i++) {
      // 'l'이 아니면 카운트를 증가시키지 않는다.
      if (string[i] !== search) continue;
    
      count++;
      // code
    }
    

© 2021. All rights reserved.

Powered by Hydejack v9.1.6