코드를 작성하다보면 if 문, switch 문 등 조건에 맞는 작동이 필요할 때가 너무도 많이 있다. 이러한 문을 제어문이라 하는데, 이 밖에도 여러가지가 있기에, 한번 더 깊게 알아보도록 하자.
제어문(control flow statement)은 조건에 따라 코드 블록을 실행하거나 반복 실행할때 사용한다. 일반적으로 코드는 위에서 아래 방향으로 순차적으로 실행되는데, 이를 인위적으로 제어할 수 있게 해준다.
물론 과도한 제어문의 사용은 직관성을 떨어트리는 결과를 초래한다. 차례대로 코드를 읽어나갈 수 있는 가독성은 오류를 줄여줄 수 있기에 사용 시 주의를 요하고 있다.
그렇다 한들 모두가 알겠듯이 제어문은 너무나도 필수적이기에 복잡하더라도 차근차근 학습을 해야한다. 정말로 필수적이다!
8-1. 블록문
블록문(block statement/compound statement)은 0개 이상의 문을 중괄호로 묶은 것으로, 코드 블록 또는 블록이라고 부르기도 한다. 자바스크립트에서는 블록문을 하나의 실행 단위로 취급한다. 블록문에는 함수 선언문이나, 제어문 등을 예시로 생각할 수 있겠다. 뭔가 끝에는 세미클론을 달아야 할 것 같지만, 블록문에서의 마지막 닫는 중괄호는 종료의 의미이기에 세미클론은 필요없다.
사실 블록이라는 개념은 자바스크립트에서 가지는 의미가 크다. 블록문이 하나의 실행단위라는 점을 상기해봤을 때, 블록 내부와 외부에서의 변수 선언, 블록문을 응용한 싱글톤패턴, let 과 const 의 등장 이유 등 중요한 파트이기에 추후에 더 자세히 다뤄볼 것이다.
// 제어문
var x = 1;
if (x < 10) {
x++;
}
// 함수 선언문
function sum(a,b) {
return a + b;
}
8-2. 조건문
흔히 들었던 조건문은 주어진 조건식의 평과 결과에 따라 코드 블록(블록문)의 실행을 결정한다. 조건식은 불리언 값으로 평가될 수 있는 표현식이다. 즉, 조건에 해당하지 않는다면 그냥 다음 코드로 넘어간다는 의미다. (중요!)
1) if...else...
가장 대표적인 조건문 형식으로, 논리적 참 또는 거짓에 따라 실행할 코드 블록을 결정한다. 결정한다라는 것은 결국 참이나 거짓이냐에 따라 정해진 코드 블록이 있다는 의미이다.
예시 코드를 보면서 익혀보는게 훨씬 간단할 것이다.
var num = 2;
var kind;
// if 문
if(num > 0){
kind = 'plus'; // 음수를 구별할 수 없다.
}
// if..else.. 문
if(num > 0){
kind = 'plus';
}else{
kind = 'minus';
} // 0은 음수가 아니다.
//if..else if..
if(num > 0){
kind = 'plus';
}else if(num < 0){
kind = 'minus';
}else{
kind = '0';
}
보면 알겠지만, else 와 else if 는 선택사항이다. else if 는 여러번 사용할 수 있다. 만일 위 예제처럼 반환값이 좀 더 정교해야 한다면 else if 를 활용하자.
만일 코드 블록 내의 문이 하나뿐이라면 중괄호를 생략할 수 있다.
var num = 2;
var kind;
if (num > 0) kind = 'plus';
else if (num < 0) kind = 'minus';
else kind = '0';
대부분의 if 문은 삼항 조건 연산자로 변경할 수 있는데, 위 예제를 변경하면
var kind = num ? (num > 0 ? 양수 : 음수) : 영;
저번 글에서 설명했듯이 삼항 조건 연산자는 값을 할당할 수있는 표현식이기에 변수에 바로 할당할 수 있다. 상황에 맞게 사용하도록 하자.
2) switch
switch 문은 주어진 표현식을 평가하여 그 값과 일치하는 표현식을 갖는 case 문으로 실행 흐름을 옮긴다. 낯설 수 있으니 형식을 알아보자
switch (표현식) {
case 표현식1:
switch 문의 표현식과 표현식1이 일치하면 실행될 문;
break;
case 표현식2:
switch 문의 표현식과 표현식2이 일치하면 실행될 문;
break;
default:
switch 문의 표현식과 일치하는 case 문이 없을 때 실행될 문;
}
if 문의 경우 조건식이 불리언으로 표현되어야 한다. 하지만 switch 문의 경우 불리언 값보다 문자열이나 숫자 값인 경우가 많다. 따라서 다양한 상황에 따라 실행할 코드 블록을 결정할 때 사용한다.
다만, 사용시에 주의할 점이 있는데 아래 예제를 보자.
var month = 11;
var monthName;
switch(month){
case 1 : monthName = "January";
// 생략
case 11 : monthName = "November";
case 12 : monthName = "December";
default : monthName = "Invaild month";
console.log(monthName) // Invaild month
분명 11월을 가르켜야 하는데, default 값을 반환하였다. 위 switch 양식과 지금의 예제의 차이점은 break 에 있다. 만일 break 를 걸어주지 않으면, case 11 을 실행한것은 맞지만, 실행한 후 switch 문을 탈출하지 않고 switch 문이 끝날 때 까지 이후의 모든 case 문과 default 문을 실행하게 된다. 이러한 현상을 폴스루(fall through) 라고 한다. 처음 november 가 할당된 뒤 그 이후로 추가적으로 재할당이 이루어진것이다.
만일 의도한 값이 November 라면 반드시 break 를 적어주어 문을 실행한 뒤 탈출하도록 하자.
default 의 경우 break 를 생략하는 편이다. 어차피 탈출하기 때문이다.
8-3. 반복문
조건문과 더불어 정말로 많이 사용되는 제어문이 반복문이다. 반복문(loop statement)은 조건식의 평가 결과가 참인 경우 코드 블록을 실행한다. 그 이후 조건식을 다시 평가하여 여전히 참인 경우 코드 블록을 다시 실행한다. 조건식이 거짓일 때까지 반복한다.
가장 기본적으로 for 문을 들 수 있다.
for (var i = 0; i < 2; i++){
console.log('히트');
}
// i = 0 일 때 i < 2 이고 히트, 그리고 i = 1
// i = 1 일 때 i < 2 이고 히트, 그리고 i = 2
// i = 2 일 때 i < 2 가 거짓이기에 멈춘다.
// 따라서 총 히트는 2번 출력된다.
for 문을 해석할때는 직접 종이에다가 각각의 상황을 그려가면서 파악하는게 가장 빠르게 감을 잡을 수 있다. 주의할 점은 조건문이 참일 때, 실행의 흐름이 블록으로 이동한다는 점이다. 즉, 히트를 출력한 다음 i 가 증가한다.
또한 처음 보면 햇갈릴 수 있는 부분이 var i = 0; 인데 이러한 변수 선언은 처음 딱 한번만 일어난다. 그러니 신경쓸 것 없다.
이러한 증감은 당연히 역으로 감소되는 상황을 가정할 수도 있다. i-- 으로 표현한다. 역시나 직접 타이핑하거나 그려보면서 상황을 인지하는게 가장 학습에 빠르다.
역시나 많이 경험했을 중첩 반복문 역시 가능하다. 중첩 for 문이라고도 하는데, 표현은 다음처럼 할 수 있다.
for(var i = 1; i <= 6; i++){
for(var j = 1; j <= 6; j++){
if(i+j===6) console.log(`[${i}, ${j}]`)
}
}
두 개의 주사위를 던졌을 때 두 눈의 합이 6이 되는 모든 경우의 수이다. 이런식으로 활용할 수 있다. 다만 2중을 넘어서 3중 4중으로 갈 수록 시간복잡도가 비약적으로 증가하기에 사용할 때 주의가 필요하다.
for 문과 더불어 while 문을 살펴보자. while 문은 주어진 조건식의 평가 결과가 참이면 코드 블록을 계속해서 반복 실행한다. for 문은 반복 횟수가 명확할 때 주로 사용하고 while 문은 반복 횟수가 불명확할 때 주로 사용한다.
역시나 조건문이 거짓인 경우 블록 코드를 실행하지 않고 종료한다. 조건문이 불리언 값이 아니라면 강제로 불리언값으로 변환하여 판단한다. (암묵적 변환)
var count = 0;
while (count < 3){
console.log(count);
count++;
}
카운트를 한번씩 증가시켜주면서 3보다 작을때까지 실행한다. (그때까지가 조건문이 참이니깐)
여기서 다시 한번 집고 넘어갈 점은 조건문이 참이면 --> 코드 블록을 실행한다 이 부분이다. 이와 반대되도록 작동하는 while 문이 있는데 그것이 do...while 문이다.
var count = 0;
do {
console.log(count);
count++;
}while(count < 3);
// count 0 출력 --> count = 1 , 조건식 count < 3 true
// count 1 출력 --> count = 2 , 조건식 count < 3 true
// count 2 출력 --> count = 3 , 조건식 count < 3 false --> 탈출
위 처럼 do 부분의 블록을 먼저 실행하고 그 다음 조건식을 따지게 되기에, 무조건 블록 한번은 실행하게 되는 특징을 가진다.
8-4. break 문
앞에서 살펴보았듯 break 문은 코드 블록을 탈출한다. 정확히 표현하자면 블록이 아니라 레이블 문, 반복문 또는 switch 문의 코드 블록을 탈출한다. if 문에 break 사용하면 오류가 난다.(SyntaxError : 문법에러)
일반적으로 중첩 for 문에서 break 를 사용시 내부 for문을 탈출하여 외부 for 문으로 돌아간다. 이처럼 break 문은 반복문을 더 이상 진행하지 않아도 될 때 불필요한 반복을 회피할 수 있어서 유용하다.
다음은 문자열에서 특정 문자의 인덱스(위치)를 검색하느 예.
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; // 반복문을 탈출한다
}
}
물론 indexOf 메서드를 활용하면 더 쉽게 index를 구할 수 있지만, break 의 사용에 대해 알 수 있다.
8-5. continue 문
조금 낮선 문인데, break 와 비슷하면서도 차이점을 보인다. continue 문은 반복문의 코드 블록 실행을 현 지점에서 중단하고 반복문의 증감식으로 실행 흐름을 이동시킨다. break 문처럼 반복문을 탈출하지는 않는다.
문자열에서 특정 문자 개수를 세는 예시다.
var string = "Hello World";
var search = 'l';
var count = 0;
//문자열은 유사배열이기에 for 문으로 순회가능
for(var i = 0; i < string.length; i++){
if(string[i] !== search) continue;
count++;
}
// 참고로 match 메서드를 사용해도 같은 동작을 한다.
const regexp = new RegExp(search, 'g');
console.log(string.match(regexp).length); // 3
사실 카운트를 증가시키는 반복문은 말 그대로 조건식을 바꾸어서 그냥 continue를 사용하지 않아도 된다. 다만 if 문 자체에서 실행해야할 코드의 수가 많아진다면, continue 를 사용하는것이 가독성 면에서 좀 더 유리하다. 결국은 사용자의 편의에 따라 사용을 하면 된다.
다음에는 타입 변환에 대해 살펴보겠다.
'Programing > Javascript' 카테고리의 다른 글
[Deep Dive] 객체 리터럴 (1) | 2022.10.23 |
---|---|
[Deep Dive] 타입 변환과 단축 평가 (0) | 2022.10.22 |
[Deep Dive] 연산자 (0) | 2022.10.19 |
[Deep Dive] 데이터 타입 (2) | 2022.10.07 |
[Deep Dive] 표현식과 문 (0) | 2022.10.06 |