본문 바로가기
Programming/JavaScript

[JS] 자바스크립트 조건문, 반복문

 

*해당 포스팅은 김기수의 '코딩 자율학습 HTML + CSS + 자바스크립트' 도서를 참고했습니다.*

 

 

조건문

조건문을 사용하면 특정 조건에 따라 다르게 실행되는 코드를 작성할 수 있다. 자바스크립트의 조건문은 대표적으로 if문과 switch문이 있다.

 

if

if문은 if 뒤에 오는 소괄호 안의 조건식이 참으로 평가되면 중괄호 안의 코드를 실행하는 조건문이다. 조건식은 어떤 자료형이든 참/거짓으로 평가되며, 결과에 따라 중괄호 안의 코드를 실행하거나 실행하지 않는다.

예를 들어, 짝수를 판별하는 조건문을 작성한다고 가정해보겠다.

let num =10;
if(num % 2 === 0){
	console.log("변수 num에 할당된 숫자는 짝수입니다.");
}

 

숫자를 2로 나머지 연산했을 때 0이라면 그 수는 짝수다. 이러한 원리를 이용해 조건식을 작성햇다. 10을 2로 나눴을 때 나머지는 0이다. (num % 2 === 0)이 성립되므로 중괄호 안의 console 명령문이 실행된다. 만약 2로 나눈 나머지가 0이 아닐 때를 처리하려면 어떻게 할까?

 

let num =10;
if(num % 2 === 0){
	console.log("변수 num에 할당된 숫자는 짝수입니다.");
} else{
	console.log("변수 num에 할당된 숫자는 홀수입니다.");
}

if문 뒤에 else문을 추가하면 된다. 단, else문은 if문 없이 단독으로 사용할 수 없으며, 하나의 if문에는 하나의 else문만 사용가능하다.

 

else if

else if문은 if문에 조건을 추가하고 싶을 때 사용한다. else if문의 개수에는 제한이 없지만, else문과 마찬가지로 단독으로 사용할 수 없고 항상 if문 다음에 사용하고 else문 보다는 먼저 사용해야 한다.

let num = 0;

if (num > 0) {console.log("양수");}
else if(num < 0) {console.log("음수");
else {console.log("0");

 

 

switch

switch문은 switch 뒤에 오는 소괄호 안의 값과 일치하는 case문이 있을 때 해당 코드를 실행하는 조건문이다. 일치 여부 확인은 연산자(===)를 사용한 비교 연산처럼 값과 자료형을 함께 비교한다. switch문에는 하나 이상의 case문과 default문, break문을 사용한다.

 

let food = "melon";

switch(food){
	case "melon":
    	console.log("fruit");
        break;
    case "carrot":
    	console.log("vegetable");
        break;
    default:
    	console.log("음식과 과일이 아니다.");
        break;
}

switch문의 소괄호에 food를 넣었다. case 중 food와 일치하는 case가 있다면 해당 중괄호를 실행하고 break를 수행한다. 만약 case에 break를 넣지 않는다면 그 이후 case까지 전부 다 실행하게 된다. 때문에 의도적으로 생략해서 작성하기도 한다. 만약 일치하는 case문이 없다면 default를 수행한다. 

 

if vs switch

그렇다면, if 와 switch의 차이점은 무엇일까? 우선 케이스 조건문임은 확실하다. 하지만 if는 조건"식"을 사용하는 반면  switch는 조건에 값(value)를 사용한다. 만약 A학점을 매기는 예제를 각각 만들어보면 어떨까?

let score = 90;
if(score >= 90 && score < 100){
	console.log("A+학점");
}
let score = 90;
switch(score){
    case 90:
    .
    .
    .
    case 98:
    case 99:
    	console.log("A+학점");
}

아마 차이가 보일 것이다. 범위 조건의 경우 if문은 한 줄의 조건만 작성하면 되지만, 값 하나만 비교하는 switch의 경우 모든 case의 값을 작성해야 한다는 단점이 있다. 

따라서 범위를 이용한 조건을 작성할 때는 if문이 적합하고, 값이 하나일때는 switch문이 더 적합하다. 상황에 맞게 알맞게 사용한다면 효율을 높일 수 있다.

 

 

반복문 

반복문은 지정한 조건이 참(true)로 평가되는 동안 중괄호(블록문) 아늬 코드를 반복해서 실행하는 문법이다. 

 

while

반복문 중 가장 기본이다. whlie문은 특정 조건을 만족하는 동안 블록문을 실행한다.

반복문을 왜 사용할까? 우선 1부터 5까지 작성해야 한다는 상황을 가정해보자. 우리가 기본적으로 아는 출력 방식은 console.log를 찍는 것이다.

console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5);

어쨌든 실행 결과는 성공적이다. 하지만, console.log를 계속 5번 반복해서 적어야한다는 단점이 있다. while문은 이를 해결해줄 수 있다.

let num = 1;
while(num <= 5){
    console.log(num);
    num++;
}

아직까지는 큰 차이가 보이지 않을 수도 있다. 하지만 만약 1부터 100000까지 출력해야 한다면? console.log를 무한대로 작성할 수도 없는 법이다. 그럴 때 반복문을 사용하는 것이다.

let num = 1;
while(num <= 9999999){
    console.log(num);
    num++;
}

 

🚫 무한 루프(Loop)

반복문, 특히 while문을 사용할 때 가장 중요한 점이 바로 무한 루프에 빠지는 것이다. while문을 사용할 때는 조건을 자세히 작성해야한다. 위와 같은 예제에서 만약 num을 증가시키는 문장이 없었다면? 아마 계속 1이 무한대로 반복해서 출력될 것이다. 

 

do...while

do-while문은 특정 조건이 참으로 평가되는 동안 do 다음에 오는 블록문을 반복 실행한다. while문은 블록문을 실행하기 전에 조건을 평가하지만, do-while문은 일단 한 번 실행한 후에 조건식을 평가한다는 차이가 있다.

do{// 첫 출력
    console.log("첫 출력");
}while(false);

while(false){ //실행되지 않는다.
    console.log("첫 출력);
}

위 예시를 보자. 조건이 false면 while문은 실행되지 않는다. 하지만, do while문은 일단 한번 실행 후에 조건을 평가한다. 그래서 "첫 출력"이 성공적으로 출력됐다.

 

for

for문은 횟수를 지정하고 그 횟수가 끝날 때까지 블록문을 반복 실행하는 반복문으로, 조건식과 증감식이라는 구조로 이뤄져있다. 

for(초기값; 조건식; 증감식){
    // 명령문
}

 

예시를 살펴보자.

for(let i =0;i<=5;i++){
	console.log(i);
}

실행 순서를 살펴보겠다.

 

1. 반복문이 실행 될 변수 i 값을 0으로 초기화한다.

2. 변수 i의 값이 5보다 작은지 평가한다. 

3. 5보다 작다면 명령문을 실행, 5보다 크다면 반복문을 종료한다.

4. 명령문을 실행했다면 i를 1 증감한다.

5. 위와 같은 내용을 계속 반복한다.

for문 중첩

for문도 중첩해서 사용할 수 있다. 
for(let i = 0; i<=5; i++){
   for(let j = 0; i<=3; i++){
   		console.log(i,j);
   }
}​

간단하게 말하자면, 외부 for문의 i가 0일 동안 내부 for문의 j가 3이 될때가지 반복한다. 즉, 외부가 1번 반복할 때 내부의 for문은 3번을 반복하는 것. 반복문을 쉽게 사용할 수 있다는 장점이 있지만, 복잡도가 n^2이 되므로 알고리즘이나 자료구조를 구현할 때 생각보다 효율이 떨어지고 시간이 오래 걸릴 수 있다. 따라서 중첩은 최소한으로 사용하는 것이 바람직하다.

 

 

 

for문을 사용한 배열 출력

for문을 이용해 배열과 같은 자료형을 반복 횟수 용도로 사용할 수 있다.

let arr = ["banana", "apple", "orange"];
for(let i = 0; i < arr.length; i++){
	console.log(arr[i]);
}

우선 배열은 아직 살펴보지 않았지만, 같은 자료형으로 모인 객체라고 생각하자. for문을 돌 것인데 arr.length는 배열의 크기다. 즉, i가 0부터 3이 될 때까지 반복하는 것. 배열은 배열이름[인덱스] 형태로 접근할 수 있다. 하지만 배열과 같은 객체 리터럴은 반복 접근할 수 있는 방식이 있다. 

0️⃣for...in 
let obj = {name: "철수", age:"20"};
for(let key in obj){
	console.log(key + ": "+obj[key]);
}​

 

for-in문으로 객체 리터럴을 반복 탐색하면 탐색 결과로 가변수(key)에 객체 리터럴의 키가 할당 되어 객체 리터럴의 키와 값을 출력할 수 있다. 

1️⃣ for...of
arr = [1,2,3,4,5];
for (let num of arr) {
    console.log(num);
}​

배열의 인덱스에 접근하지 않고도 출력할 수 있다. 보통 배열에 접근하는데 사용하는데, for...in과 같은 역할을 하지 않는다. 객체 리터럴의 속성에 접근하려 할 경우 TypeError가 발생한다.

2️⃣ forEach()
forEach()는 메서드다. 배열의 각 요소에 대해 지정된 함수를 한번씩 호출한다. 일반적으로는 배열을 순회하면서 각 요소에 대해 특정 작업을 수행할 때 사용된다. 반복적으로 실행될 콜백 함수를 인수로 받는다.
const arr = [1, 2, 3, 4, 5];

arr.forEach(function(element) {
    console.log(element);
});​

 

가독성있고 간결하며, 배열 각 요소에 콜백 함수가 자동으로 호출되어 반복 작업에 편리하다. 하지만, 동기적 처리로 인해 비동기 작업에는 적합하지 않다. 비동기 작업은 앞선 for...of문과 같은 반복문을 사용하는 게 좋다.

 

break

앞서 switch문을 살펴볼 때 break를 눈에 익혔다. 뜻 그대로 원하는 시점에 반복 중단을 할 수 있는 명령이다.

만약 10까지 반복하다가 5가되면 멈추는 반복문을 작성해보자.

for(let i = 0; i<=10; i++){
    if(i === 5){break;}
    console.log(i);
}

이는 for...in을 사용할 때도 마찬가지다. 

 

continue

break문이 반복문을 즉시 종료하는 명령이라면, continue느 반복문을 건너뛰고 실행하라는 명령이다. 1부터 10까지 반복하는데 짝수일 경우만 출력하고 싶다고 가정해보자. 아래와 같이 작성할 수 있을 것이다.

for(let i = 1; i<=10; i++){
    if(i % 2 == 0){continue;} //중괄호를 생략해도 된다.
    console.log(i);
}

i가 짝수가 될 경우 continue를 통해 아래 반복문 명령을 실행하지 않고 다음으로 넘어간다.