제어문

모던 자바스크립트 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 ...elseswitch
두 가지 조건문을 제공한다.
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)은 조건식의 평가 결과가 참인 경우 코드 블록을 실행한다. 그 후 조건식을 다시 평가하여 여전히 참인 경우 코드 블록을 다시 실행한다. 이는 조건식이 거짓일 때까지 반복한다.
자바스크립트는
forwhiledo ...while
의 반복문을 제공한다.
for 문
for문은 조건식이 거짓으로 평가될 때까지 코드 블록을 반복 실행한다.
for (변수 선언문 떠는 할당문; 조건식; 증감식) {
조건식이 참인 경우 반복 실행될 문
}
for문for (var i = 0; i < 2; i++) { console.log(i); }

① 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 }