본문 바로가기

Javascript/Clean Code

4. 분기 다루기 - 2(else if/else 피하기, Early Return, 부정 조건문 지양, Default Case, 명시적인 연산자, Nullish coalescing operator, 드모르간의 법칙)

■ 순서

5.else if 피하기

6.else 피하기

7.Early Return

8.부정 조건문 지양하기

9.Default Case 고려하기

10.명시적인 연산자 사용 지향하기

11.Nullish coalescing operator

12.드모르간의 법칙

 

 


5.else if 피하기

: else if를 promise의 then처럼 계속 연속적으로 실행이 된다고 생각하는 사람들이 많다.

 

아래는 첫번째가 실행된다.

const x = 1;

if (x >= o) {
  'x는 0과 같거나 크다';
} else if (x > 0) {
  'x는 0보다 크다 ';
} else {
  'Else';
}

 

위는 아래 같이 나타낼 수도 있다. 

: else if를 한번 시작하면 계속적으로 스위치 문을 사용하는 것과 같다.

const x = 1;

if (x >= o) {
  'x는 0과 같거나 크다';
} else { if (x > 0) {
  'x는 0보다 크다 ';
  }
}

 

그럼 어떻게 해야될까?

그냥 명확하게 아래와 같이 조건을 분리를 하는 것이 좋다.

const x = 1;

if (x >= o) {
  'x는 0과 같거나 크다';
}  

if (x > 0) {
  'x는 0보다 크다 ';
}

6.else 피하기

 

위의 함수는 아래와 같이 바꿔도 상관이 없다.

function getActiveUserName(user) {
  if (user.name) {
    return user.name;
  } else {
    return '이름없음';
  }
}

//위는 굳이 else를 쓰지 않아도 된다. 
//아래와 같이 else를 없애도 상관이 없다. 

function getActiveUserName(user) {
  if (user.name) {
    return user.name;
  }
  
  return '이름없음';  
}

 

예시

function getHelloCustomer(user) {
  if (user.age < 20) {
    report(user);
  } else {
    return '안녕하세요';
  }
}

//위의 함수는 원래 아래와 같은 함수였다.
function getHelloCustomer(user) {
  return '안녕하세요';  
}

//하지만 성인이 아닐 때만 이름을 실행하게 하려고 위의 함수를 만든 것이다.
//하지만 그렇게 되면 안녕하세요는 나오지 않기 때문에, 이 부분도 else를 버리자.
//else는 습관이 되면 좋지 않다.

 


7.Early Return

 

아래의 함수는 주석이 달려있는 것처럼 작동한다.

 

function loginService(isLogin, user) {
  if (!isLogin) {  //Login이 안되어 있으면
    if (!checkToken() {  //Token이 있는지 확인해봄
      if (user.nickName) {  // nickname에 존재 하지 않으면 회원가입 안되어 있으므로
        return registerUser(user); // 회원가입으로 넘김
      } else {
        refreshToken();  //아니면 token을 새로고침
      
        return '로그인 성공';  // 리턴을 반환
      }
    } else {
        throw new Error('No Token'); 
  }
}

 

예제1)

function loginService(isLogin, user) {
  // Early Return
  // 로그인이 되어있으면, Early Return 시켜버린다.
  if (isLogin){
    return 
  }
  // 그다음에 토큰 확인
  if (!checkToken() {  
   throw new Error('No Token');
  }
  // 그다음에 아이디 확인
  if (!user.nickName) {  
        return registerUser(user);
  }
  // 그 다음에 새로고침 및 로그인
  refreshToken();
      
  return '로그인 성공'; 
}

 

예제2)

아래와 같이 최상위에 거르는 로직을 넣어주면 읽기도 편하고 로직이 눈에 보여서 좋다.

수많은 얼리로직은 좋지는 않지만, 하나의 조건에만 의존적으로 작성이 있을때는 얼리리턴 해주는 것이 좋다.

function 오늘하루(condition, weather, isJob) {
  if (condition === 'GOOD') {
    공부();
    게임();
    유튜브보기();
    
    if (weather === 'GOOD') {
      운동();
      빨래();
    }
    
    if (isJob === 'GOOD') {
      야간업무();
      조기취침();
    }
  }
}

//이를 아래와 같이 고쳐버린다.

function 오늘하루(condition, weather, isJob) {
  if ( condition !== 'GOOD') {
    return
  }
  
  공부();
  게임();
  유튜브보기();
    
  if (weather === 'GOOD') {
    운동();
    빨래();
  }
  
  if (isJob === 'GOOD') {
    야간업무();
    조기취침();
  }
  
}

 


8.부정 조건문 지양하기

1) 부정 조건문을 쓰면 여러번 생각을 해야된다.(그냥 isNumber를 만들자)

: 그걸 뒤집을때는 더 생각을 해야한다.

 

NaN // Not a number, Not is not defined
if (!isNaN(3)) {
  console.log('숫자입니다)
}

 

2) 프로그래밍 언어 자체로 if문이 처음부터 오고 true부터 실행시킨다.

: if-else를 뒤집은 꼴이 된다.

if (isNotCondition) {
  console.log('거짓인 경우에만 실행');
}

 

3) 부정조건문을 사용할 때

-.Early Return을 사용할때,

-.유효성 검증(Form Validation),

-.보안 혹은 검사하는 로직

 


9.Default Case 고려하기

: 기본값을 미리 정해놓는 것은 중요하다(Edge Case)

 

아래는 아무것도 넣지 않으면 1이 기본값이 된다.

function sum(x, y) {
  x = x || 1;
  y = y || 1;

  return x + y;
}

sum();

 

아래와 같은 상황도 기본값이 있게 된다.

 function createElement(type, height, width) 
   const element = document.createElement(type || 'div');
   
   element.style.height = height || 100;
   element.style.width = width || 100;
   
   return element; 
 }
 
 createElement()

 

 

만약 사용자가 아래와 같이 잘못썼을 경우를 대비하여 기본값을 설정해주어야 한다.

function registerDay(userInputDay) {
  switch (userInputDay) {
   case '월요일':  //some code   
   case '화요일':  //some code   
   case '수요일':  //some code   
   case '목요일':  //some code   
   case '금요일':  //some code   
   case '토요일':  //some code   
   case '일요일':  //some code   
   default:
     throw Error('입력값이 유효하지 않습니다.')   
  }
}

e.target.value = '월ㄹ요일';
registerDay(e.target.value);

 

정리

: 언제나 기본값을 정해주는 것이 좋다.

(특히 parseInt의 두번째 값은 기본값이 10진수가 아니다! 그런 것들도 아래와 같이 래핑해서 사용하자.)

function safeParseInt(number, radix) {
  return parseInt(number, radix || 10);
}

10.명시적인 연산자 사용 지향하기

: 연산자를 외우기 보다는, 안전하게 사용하는 것이 좋다

(괄호를 써주도록 한다.)

: 예측 가능하고 디버깅 하기 쉽게 한다.

 

(isLogin && token) || user

 

아래도 오히려 줄이기보다 명시적으로 만드는 것이 좋다.

number--; // 이것보다

//아래와 같이 명시적으로 작성한다.
number = number -1;

 


11.Nullish coalescing operator

: 나름 최근 연산자여서, 최근꺼에만 돌아갈 수도 있다.

 

function createElement(type, height, width) {
  const element = document.createElement(type || 'div');
  
  element.style.height = String(height || 10) + 'px';
  element.style.width = String(width || 10) + 'px';
  
  return element;
}


const el = createElement('div', 0, 0); 

el.style.height // 실행하면 10px이 나온다. 숫자 0은 falsy에 해당되기 때문에, 10이 된다.

 

 

null 이거나 undefined 일때만 널 병합연산자인 "??"를 써서 뒤에 값이 사용될 수 있게 해준다.

아래와 같이 0이 나오게 된다.

: 0은 null과 undefined에 해당되지 않기 때문에, 0 그대로가 출력된다.

function createElement(type, height, width) {
  const element = document.createElement(type || 'div');
  
  element.style.height = String(height ?? 10) + 'px';
  element.style.width = String(width ?? 10) + 'px';
  
  return element;
}


const el2 = createElement('div', 0, 0);

el2.style.height //0
el2.style.width //0

 

하지만 이건 부작용이 나타나게 된다.

|| 를 사용할지 ??를 사용할지 헷갈리게 된다.

null || undefined ?? "foo" 
// Error가 나온다.
// ??와 ||을 직접적으로 혼합해서 쓰면 에러가 나온다.
// 사람들이 실수를 많이 해서 문법적으로 제약을 시켰음.

12.드모르간의 법칙

: 드모르간의 법칙으로 아래와 같이 풀어주는 것이 좋다.

: true is not true, false is not false

 

const isValidUser = true; //서버에서
const isValidToken = true;  /서버에서

if (isValidGToken && isValidUser) {
  console.log('로그인 성공!');
}


if (A && B) {
  //성공
}

if !(A && B) {
  //실패
}

if (!A || !B) {
  //실패
}