📝

4. 조건문

4-1. 조건문이란?

조건문이란 주어진 조건에 따라 코드들의 실행이 결정되는 문(statement)이다.

4-2. if문

if문의 기본적인 형태는 아래와 같다.
 
if (조건식) { // 조건식이 참일 경우 실행될 코드 }
 
조건식이 참이라고 평가가 되면 중괄호 안의 코드들이 실행되는 것이 if문의 기본 구조라고 할 수 있다. 중괄호안의 코드가 한 줄 뿐이라면 중괄호를 아래와 같이 생략해서 쓸 수 있다.
 
if (true) console.log("중괄호를 생략했습니다.");
 
코드를 여러사람이 같이 보게 될 경우 가독성을 위해 생략하지 않는 것을 추천한다.

4-2-1. if ... else문

if문을 단독으로 사용할 수 있지만 대부분의 경우에 if ... else 문을 활용한다. 하나의 조건이 아닌 여러개의 조건을 평가해야 하는 상황이 많기 때문이다. if ... else문의 기본적인 형태는 아래와 같다.
 
if (조건식1) { // 조건식1이 참(true)일 경우 실행될 코드 } else if (조건식2) { // 조건식1이 거짓(false)이고 조건식2가 참(true)일 경우 실행될 코드 } else { // 조건식1, 2 모두 거짓일 경우 실행될 코드 }
 
상황에따라 조건식을 추가하고 싶으면 else if문을 여러번 작성해도 된다.
 
if (조건식1) { // 조건식1이 참(true)일 경우 실행될 코드 } else if (조건식2) { // 조건식1이 거짓(false)이고 조건식2가 참(true)일 경우 실행될 코드 } else if (조건식3) { // 조건식1, 2이 거짓(false)이고 조건식3이 참(true)일 경우 실행될 코드 } else if (조건식4) { // 조건식1, 2, 3이 모두 거짓(false)이고 조건식4가 참(true)일 경우 실행될 코드 } else { // 위의 조건식들이 모두 거짓일 경우 실행될 코드 }
 
if문은 참(true)인 조건식을 만나게 되면 코드블록을 실행하고 해당 조건문을 빠져나오게 된다.
 
if (true) { console.log('조건문을 빠져나갈거에요!'); } else if (조건식) { /* ...10,000줄의 코드... */ } else { // 위의 조건식들이 모두 거짓일 경우 실행될 코드 }
 
위의 코드에서 첫번째 조건 평가에서 참(true)을 만났으므로, 뒤에 10,000 줄의 코드가 있더라도 조건문을 빠져나오게 된다. if문의 특징은 참(true)인 조건식이나 else문을 만나기 전까지는 조건문을 빠져나오지 않는다는 것이다.
 
지금까지 알아본 내용을 바탕으로 하나의 단순한 프로그램을 만들어보자. 아래는 커피의 가격을 입력하면 미리 정해둔 조건에 따라 해당 커피의 가격이 어떠한지 알아보는 코드이다.
 
function coffePrice(price) { if (price > 6000) { console.log('커피가 너무 비싸요!'); } else if (price < 3000) { console.log('맨날 먹어도 되겠네요!'); } else { console.log('적당한 가격대입니다.'); } }
 
else문은 앞서 나온 조건들이 모두 거짓일 경우 무조건 실행될 코드이다. 분기처리를 해줄 때 모든 상황을 고려하여 조건을 명시하지 않아도 되는 상황에는 else문을 사용해도 좋다. 그러나 else문은 프로그래머가 예상 못한 오류와 관련된 처리를 해주는 것이 일반적이다. 또한 else문 자체를 사용하지 않아도 오류는 없다.

4-2-2. if문 중첩

우리는 위에서 커피가격을 입력하면 가격을 판단하여 문구를 출력할 수 있었다. 그런데 아래와 같은 상황을 살펴보면 이상한 부분이 있다.
 
notion imagenotion image
 
분명 가격이 삼만원임에도 불구하고 적당한 가격임을 알리는 문구를 출력했다. 이유는 예상하지 못한 문자열을 받았기 때문이다. 이 때에는 입력받은 값이 숫자라면 위에서의 if문을 실행시켜주고 입력받은 값이 숫자가 아니라면 숫자를 입력하라는 문구를 출력해주면 된다. 이렇듯 동시에 만족해야할 조건이 여러개라면 우리는 if문을 중첩해서 쓸 수 있다.
 
function coffePrice(price) { if (typeof price === 'number') { // 타입이 숫자형이면서, if (price > 6000) { // 그 값의 크기가 작성한 조건을 만족해야 한다. console.log('커피가 너무 비싸요!'); } else if (price < 3000) { console.log('맨날 먹어도 되겠네요!'); } else { console.log('적당한 가격대입니다.'); } } else { // 입력값이 숫자가 아닌 모든 경우에는 숫자로 입력하라는 문구를 출력한다. console.log('가격을 숫자로 입력해주세요!'); } }
 
위의 코드는 아래와 같이 쓸 수 있다. 같은 내용이더라도 작성방법에는 다양한 방법이 있다는 것을 알아두자.
 
// 타입을 확인한 뒤 false라면 함수를 종료시키는 방법 function coffePrice(price) { if (typeof price !== 'number') { console.log('가격을 숫자로 입력해주세요!'); return; } if (price > 6000) { console.log('커피가 너무 비싸요!'); } else if (price < 3000) { console.log('맨날 먹어도 되겠네요!'); } else { console.log('적당한 가격대입니다.'); } }
// 숫자인 상황에 대해서 모든 상황을 확인한 뒤, 그 외의 경우는 else문으로 처리 function coffePrice(price) { if (price > 6000) { console.log('커피가 너무 비싸요!'); } else if (price < 3000) { console.log('맨날 먹어도 되겠네요!'); } else if (price >= 3000 && price <= 6000) { // 논리연산자의 내용은 뒤에 있습니다. console.log('적당한 가격대입니다.'); } else { console.log('가격을 숫자로 입력해주세요!'); } }

4-3. switch문

switch문은 표현식의 값에 따라 일치하는 경우를 찾아가서 코드를 실행시키는 조건문이다. 아래의 코드가 switch문의 기본적인 형태이다.
 
switch (값) { case 값1 : // 실행시킬 코드 break; case 값2 : // 실행시킬 코드 break; case 값3 : // 실행시킬 코드 break; case 값4 : // 실행시킬 코드 break; default : // 일치하는 경우가 없을 때 실행시킬 코드 break; };
 
switch문의 특징은 다음과 같다.
  • switch 뒤에 오는 표현식들의 값에 따라 실행시킬 코드가 있는 곳으로 실행을 옮겨간다.
  • 코드실행을 한 뒤, break에 의해서 조건문을 빠져나오게 된다.
  • 표현식이 case와 일치하는 경우가 없다면 default 문으로 이동하게 된다.
  • default 문은 선택사항이다.
 
switch문을 이용해 간단한 예제를 살펴보자.
 
let price = 0; let menu = '카페라떼'; // 메뉴를 바꿔가면서 콘솔창에 입력해보자. switch (menu) { case '아메리카노': price = 4000; break; case '카페라떼': price = 5000; break; case '바닐라라떼': price = 6000; break; case '콜드브루': price = 5500; break; case '딸기라떼': price = 7000; break; case '레몬에이드': price = 6500; break; case '에스프레소': price = 3500; break; case '루이보스': price = 4500; break; default: console.log('메뉴를 정확히 입력하세요.'); }
 
위의 코드를 if문으로 작성할 수 있지만 종류가 많아지고 마지막 메뉴의 가격을 정하려면 쓸데없이 많은 else if 조건식을 판별하게 될 것이다.

4-3-1. break

각각의 case마다 break; 라는 코드를 작성해 주었다. 만약 해당 코드가 없다면 어떤 결과가 나오는지 알아보자.
 
let price = 0; let menu = '카페라떼'; // 메뉴를 바꿔보세요! switch (menu) { case '아메리카노': price = 4000; case '카페라떼': price = 5000; case '바닐라라떼': price = 6000; case '콜드브루': price = 5500; case '딸기라떼': price = 7000; case '레몬에이드': price = 6500; case '에스프레소': price = 3500; case '루이보스': price = 4500; default: console.log('메뉴를 정확히 입력하세요.'); }
notion imagenotion image
 
default 문이 실행되어 가격이 4500이 된 것을 볼 수 있다. 즉, break가 없다면 switch문을 탈출하지 않고 모든 코드들을 실행시킨다. switch문을 적절하게 사용하고 싶다면 반드시 break를 작성해주는 것을 알아두자. switch문에서 표현식은 참이나 거짓으로 판별되는 경우가 올 수 있지만 보통의 경우에는 문자열이나 숫자인 경우가 많으며, 훨씬 더 다양한 조건에 맞게 코드를 실행할 수 있게 해준다.
 
// true를 찾아가긴 하지만, 이와 같은 경우엔 if문을 활용하는 것이 좋다. switch (true) { case true: console.log('swithch true!'); break; case false: console.log('swithch false!'); break; };
 
참, 거짓으로 코드를 실행하고자 한다면 그냥 if문을 사용하는 것이 일반적이다.
 
💡
switch문은 참이냐 거짓이냐를 판별하는 상황보다는 다양한 값을 받아오는 상황에서 코드 실행을 결정할 때 사용한다.

4-4. 삼항연산자(조건연산자)

삼항연산자는 if문과 비슷하게 동작하는 것으로 보이는 연산자이다. 그렇다면, 조건문과는 어떤점이 비슷하고 어떤점이 다른지 알아보자. 아래는 MDN에서 설명하는 삼항연산자의 기본 형태이다.[1]
 
조건식 ? 참일 경우 실행되는 표현식 : 거짓일 경우 실행되는 표현식
 
let item = true ? console.log('true') : console.log('false'); console.log(item);
notion imagenotion image
 
item이라는 변수에 참 일경우 console.log('true')가 실행되고 해당 표현식이 item에 할당된다. console.log는 반환값이 undefined이므로 item에는 undefined가 할당된다.
 
좀 더 쉬운 예제로 살펴보도록 하자.
let item = true ? 100 : 200; console.log(item);
 
notion imagenotion image
 
이처럼 삼항연산자는 코드의 실행도 해주고 값으로 사용할 수 있다는 점에서 if문과 다르다.
 
const price = 7000; const message = (price>6000) ? '비싸요!' : '안비싸요!'; console.log(message); // '비싸요!'라는 문자열을 값으로 사용하게 된다.
 

4-4-1. 삼항연산자 중첩

삼항연산자의 중첩을 활용하여 if...else 문과 동일한 코드를 작성할 수 있다.
 
let price = 5000; let message = (price>6000) ? '비싸요!' : (price<3000) ? '엄청싸요!' : '적당해요!'; // 위의 코드는 아래와 같다. let price = 5000; let message = ''; if (price > 6000) { message = '비싸요!'; } else if (price < 3000) { message = '엄청싸요!'; } else { message = '적당해요!'; }
 
삼항연산자는 대부분의 경우 짧은 코드이면서 값의 반환이 필요할 때 쓰기 좋다. 만약 중첩이 많이 쓰이거나, 가독성이 떨어진다고 판단되면 if...else문으로 우회하는 것도 좋은 방법이다.

4-5. 조건식을 작성할 때 알아두면 좋은 사항

코드블록내의 코드들을 어떻게 작성하느냐도 굉장히 중요하지만 조건문에서 가장 중요한 부분은 결국 ‘조건식’이다. 조건식의 판별결과에 따라 코드블록이 실행이 되기 때문이다.

4-5-1. Boolean 형으로의 암묵적 타입 변환

조건식이 참이냐 거짓이냐에 따라 실행이 결정되므로 조건식의 자리에 오는 식들은 참이나 거짓으로 값을 가져야하지만, 우리는 종종 불리언 값이 아닌 표현식들을 넣어두고도 진행한다. 예제는 다음과 같다.
 
let name = ''; if (name) { console.log(`안녕하세요 ${name}님! 반갑습니다.`); } else { console.log('이름이 없습니다!'); }
 
코드의 흐름대로 읽어보자면 아래와 같다.
만약 이름에 값이 있다면, 인사를 하는 문장을 출력하고 그렇지 않은 경우엔 이름이 없다는 문구를 출력하라.
 
우리는 name이라는 변수가 명확한 불리언 값이 아닌 빈 문자열임을 알고있지만 실행결과는 다음과 같다.
 
notion imagenotion image
 
분명 false가 아님에도 이름이 없다는 문구가 출력된다. 이는 자바스크립트 엔진이 조건식을 평가할 때 불리언으로 타입을 암묵적으로 변환하기 때문이다. 그렇다면 어떠한 값들이 참으로 변환이 되고 거짓이 되는지 알아보자.

4-5-5-1. falsy

타입 변환이 되었을 때 false가 되는 값들을 거짓으로 평가되는 값, falsy 값이라고 부른다.
조건식에 아래의 값이 들어오면 코드가 실행되지 않고 다음 else if문이나 else문으로 넘어가게 된다.
  • 0
  • false
  • undefined
  • null
  • "" (빈 문자열)
  • NaN
 
if (0) { console.log('0은 true가 될까요?'); } else if (false) { console.log('false는 true가 될까요?'); } else if (undefined) { console.log('undefined는 true가 될까요?'); } else if (null) { console.log('null은 true가 될까요?'); } else if ('') { console.log('빈 문자열은 true가 될까요?'); } else if (NaN) { console.log('NaN은 true가 될까요?'); } else { console.log('위의 조건식중 truthy값은 없습니다!'); }
 
위의 조건식중에서는 true로 변환이 되는 값이 없으므로 else문이 실행된다.
 
💡
빈 배열과 빈 객체는 falsy 값이 아니다!
 

4-5-5-2. truthy

타입 변환이 되었을 때 true가 되는 값들을 참으로 평가되는 값, truthy 값이라고 부르며 위의 falsy 값들을 제외한 모든 값들이 truthy 값이다. 헷갈릴 수 있는 truthy 값을 알아보자.
 
let coffeeList = []; // 빈 배열은 truthy값이다. if (coffeeList) { console.log('커피리스트 : ' + coffeeList); } else { console.log('커피 종류를 입력하세요!'); } // 위와 아래를 비교해보자 if (coffeeList.length) { // coffeeList.length는 0이므로 falsy값이다. console.log('커피리스트 : ' + coffeeList); } else { console.log('커피 종류를 입력하세요!'); }
notion imagenotion image
 
위의 코드의 경우 빈 배열임에도 불구하고 참으로 평가되어 커피리스트라는 문구를 출력하고 있다. 배열과 함께 조건문을 작성하고자 한다면 배열의 프로퍼티인 length를 이용하면 된다.

4-5-2. 논리 연산자

논리 연산자의 종류로는 and(&&), or(||), not(!)이 있다. 논리 연산자의 사용은 반복된 if문 작성이나 if문의 중첩을 줄일 수 있다.
 
  • and(&&)
 
console.log(1 && 2 && 3); // 3
 
결과 값이 3이 나오는 이유는 and(&&) 연산자는 1부터 평가를 시작해서(왼쪽부터) 첫 번째 falsy 값을 찾아가기 때문이다. 하지만 위의 피연산중에서는 falsy값이 없으므로 가장 마지막 값인 3이 출력된다.
아래의 코드와 같이 조건문처럼 사용 할 수도 있다.
 
let hello = 10>5 && 10>1 && 'hello' console.log(hello) 'hello'
 
위의 실행 순서대로 조건문에서의 and(&&)연산자의 사용을 적용해보자.
 
let price = 7000; if (typeof price === 'number' && price>6000) { // true && true == 두번째 true console.log('커피가 너무 비싸요!'); }
간단한 예제이지만, and 연산자를 이용해 if문의 중첩을 한번 줄여서 작성할 수 있다.
 
  • or(||)
 
console.log(1 || 2 || 3); // 1
 
결과로 1이 나오는 이유는 or(||)연산자는 1부터 평가를 시작해서(왼쪽부터) 첫 번째 truthy 값을 찾아가기 때문이다. 위에서는 1이 truthy 값이므로 1을 출력한다. 만약 truthy 값이 없다면 마지막 값을 반환한다.
 
// 성적이 90이상이거나 수상경력이 있다면 합격문구를 출력하는 조건문을 작성해보자 const user = { score : 70, award : 'weniv FE스쿨 우수' } if (user.score > 90) { console.log('합격입니다!'); }; if (user.award) { console.log('합격입니다!'); }; // 위와 아래코드는 동일하다. if (user.score >90 || user.award) { // false || 'weniv FE스쿨 우수' == 'weniv FE스쿨 우수' console.log('합격입니다!'); };
 
간단한 예제이지만, or 연산자를 이용해 if문의 반복을 한번 줄여서 작성할 수 있다.
 
  • not(!)
not연산자는 뒤의 피연산자를 불리언으로 형 변환을 한 뒤, 그 값의 역을 반환한다. 부정 연산자는 불리언(boolean) 값을 반환한다. 아래는 직접 about:blank 창에서 값을 확인해보자.
 
console.log(!'string'); console.log(!1); console.log(!true); console.log(!0); console.log(!''); console.log(!undefined); console.log(!null); console.log(!NaN); console.log(!false);
 
💡
1. and(&&), or(||) 연산자의 결과값은 boolean이 아니다.
2. 부정 연산자(!)의 결과값은 boolean이다.
3. and(&&) ⇒ if문의 중첩을 줄일 수 있다.
4. or(||) ⇒ if문의 반복을 줄일 수 있다.

4-6. 조건문을 쓰는 방법

조건문을 어떻게 쓰면 더 효율적일지 또 상황에 맞는 조건문에 대해서 정리해보자.
  • 참인 조건식(혹은 else문)을 만나야만 탈출하는 if문
⇒ 분기처리시에 가장 많은 경우가 발생할 것으로 예상되는 조건식을 상단에 위치시킨다.
⇒ 조건식에서 범위를 가지는 숫자형의 데이터를 판별할 때 if문을 사용한다.
⇒ if문의 중첩이나, and(&&)연산자의 활용을 적절히 해준다.
  • 일치하는 경우를 찾아가서 실행하는 switch문
⇒ 10개 이하 정도의 판별식이 필요하고 범위를 가지지 않는 데이터의 경우 switch문을 사용한다.
  • 판별해야하는 경우가 너무 많은 경우
⇒ 배열검색을 활용한다.
💡
성능면에서의 고민도 필요하지만 그보다 더 중요한 것은 공동작업을 하는 사람이 보아도 빠르게 이해가 되는 가독성 좋은 조건문을 위한 고민이 더욱 필요하다.

Reference


  1. https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Conditional_Operator