1. 분기 다루기

1) 값식문

  • 값식문이란, jsx에서 본 것과 같이 { }안에 식이 오직 값으로만 이루어진 문법을 말한다. 이 때, 값 이외의 다른 것(조건문, 수식 등)을 사용하면 에러가 발생한다.
// jsx 분기문을 작성할 때, 참고
<p>
    {(()=> {
        // jsx 분기문 다룰때 참고하자
        switch (color) {
            case 'red':
                return '#FF0000';
            case 'green':
                return '#00FF00';
            default:
                return '#FFFFFF';
        }
    })
    }
</p>

2) 삼항연산자

  • 삼항연산자를 사용할 때는 덕지덕지 사용하기 보다는 ‘3가지 기준’을 갖고 작성하는게 좋다.
  • 기준 1. 분기를 다루고 값을 바로 저장하는 경우
const welcomeMessage = (isLogin) => {
    const name = isLogin ? name : "이름 없음"

    return `어서오세요 ${name}님`
}

  • 기준 2. 연속된 분기를 다룰 때는 삼항 연산자보다 switch문이 나을 수 있음
// bad case 1
// 가독성이 떨어짐
const example = () => {
    return condition1 ? value1
        : condition2 ? value2
            : condition3 ? value3
                : value4;
}

// bad case2
// else if, else의 사용은 낭비 면에서 피하는 것이 좋다
const example = () => {
    if (condition1) { return value1; }
    else if (condition2) { return value2; }
    else if (condition3) { return value3; }
    else { return value4; }
}

// good case - switch 문으로 교체
const example = () => {
    switch (res) {
        case value:

            break;

        default:
            break;
    }
}

  • 기준 3. 삼항 연산자는 되도록 무언가의 값이 만들어지는 경우에 사용하는 것이 좋음
// bad case
// 실행에는 문제가 없지만, 삼항연산자에 실행문으로 함수를 사용하는 것은 삼항연산자의 의도와 맞지 않음
const alertMessage = (isAdult) => {
    isAdult > 19
    ? window.alert("성인입니다.")
    : window.alert("미성년입니다.")
}

// good case
// 실행문으로 함수를 사용하는 경우, if - else 가 나을 수 있음 (early return 은 뒤에서 다룸)
const alertMessage = (isAdult) => {
    if(isAdult > 19) {
        window.alert("성인입니다.");
    } else {
        window.alert("미성년입니다.");
    }
}

3) Truthy & Falsy

if (true)
if ({}) // 주의 1. 빈 배열을 Truthy 하게 봄
if ([]) // 주의 2. 빈 객체를 Truthy 하게 봄
if (42)
if ("0")
if ("false")
if (new Date())
if (-42)
if (12n)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)

if (false)
if (null)
if (undefined)
if (0)
if (-0)
if (0n)
if (NaN)
if ("")

  • 실무에서 적용해볼만 Validation 관련 코드 (단, 엄격한 검사는 아니니 주의하자)
const printName = (name) => {
    // if (name === null && name === undefined)
    if (!name) {
        return '사람이 없네요.'
    }
    return '안녕하세요 ' + name + '';
}

console.log(printName()); // 사람이 없네요

4) 단축평가

  • 단축평가는 논리연산자(and, or)로 볼 수도 있지만, 값을 바로 할당할 때는 아래와 같은 개념으로 이해하는 게 좋다.

  • &&: false 를 만나면 평가를 중지한다.

true && true && '도달 O' // '도달 O'
true && false && '도달 X' // '도달 X'
  • ll: true 를 만나면 평가를 중지한다. 예를 들어 A ll B 가 있다면, A가 false일 때 B를 저장한다.
false && false && '도달 O' // '도달 O'
true || true || '도달 X' // '도달 X'
  • 예제 1
// 원본 코드
const fetchData = (data) => {
    if (data) {
        return data;
    } else {
        return 'Fetching...';
    }
}

// 예제 1 - 삼항연산자 good case
const fetchData = (data) => {
    return data ? data : 'Fetching...'
}

// 예제 2 - 단축평가 good case
const fetchData = (data) => {
    return data || 'Fetching...'
}
  • 예제 2
// 원본 코드
const favoriteDog = (dog) => {
    let favoriteDog;

    if (someDog) {
        favoriteDog = dog;
    } else {
        favoriteDog = '냐옹';
    }

    return favoriteDog + '입니다'
}

// 예제 2 - 삼항연산자
const favoriteDog = (dog) => {

    return someDog ? `${dog} 입니다` : `${냐옹} 입니다`;
}

// 예제 2 - 단축평가
const favoriteDog = (dog) => {

    return (someDog || '냐옹') + '입니다';
}
  • 예제 3
// 원본 코드
const getActiveUserName = (user, isLogin) => {
    if (isLogin && user) {
        return user.name
    } else {
        return '이름없음'
    }
}

// 예제 3 - 단축평가
const getActiveUserName = (user, isLogin) => {
    if (isLogin && user) {
        return user.name || '이름없음'
    }
}

5) else if 피하기

  • if - else if - else 로 길어지는 경우 switch로 대체하거나, if로 코드를 명료하게 작성하는게 좋다. 왜냐면, else if 는 else 동작 후 if가 동작하는 구조이기에 조건만 확실하다면, else는 낭비이기 때문이다.
const x = 1;
if (x > 0) {
    console.log('x는 0과 같거나 크다'); // x는 0과 같거나 크다
} else if (x > 0) {
    console.log('x는 0보보다 크다');
}

// else if <- else + if 로 대체 가능하며, 두 방식 모두 낭비이다
const x = 1;
if (x > 0) {
    console.log('x는 0과 같거나 크다'); // x는 0과 같거나 크다
}
else {
    if (x > 0) {
        console.log('x는 0보보다 크다');
    }
}

6) if - else 를 습관처럼 사용하는 걸 조심하자.

  • 논리적으로 명료해서 사용하는 경우가 많지만, 스타일적으로나 함수가 여러기능을 수행하게 될 때 예상치 못한 결과가 나올 수 있다.
// bad case
const getActiveUserNAme = (user) => {
    if (user.name) {
        return user.name;
    } else {
        return '이름없음';
    }
}

// good case - early return 으로 스타일적으로 개선
const getActiveUserNAme = (user) => {
    if (user.name) {
        return user.name;
    }

    return '이름없음';
}

// good case - 단축평가(||)로 스타일적으로 개선
const getActiveUserNAme = (user) => {
    return user.name || '이름없음';
}

7) early return 을 사용하자

  • early return을 사용하면, 논리는 바뀌지 않으면서 가독성을 높일 수 있다.

  • 예제 1

// early return 적용 전
const loginService = (isLogin, user) => {
    // 로그인 여부
    if (!isLogin) {
        // 토큰 체크
        if (!checkToken()) {
            // 기가입 재확인
            if (!user.nickname) {
                return registerUser(user);
            } else {
                refreshToken();

                return '로그인 성공';
            }
        } else {
            throw new Error('No Token')
        }
    }
}

// early return 적용 후 예시
// 조건문 간의 의존성을 줄이는 효과가 있음
const loginService = (isLogin, user) => {
    // 로그인이 되어있으면, Early Return
    if (isLogin) {
        return
    }

    if (!checkToken()) {
        throw new Error('No Token');
    }

    if (!user.nickname) {
        return registerUser(user);
    }

    refreshToken();
    return '로그인 성공';
}
  • 예제 2
// early return 적용 전 예시 -2
const Todo = (condition, weather, isJob) => {
    if (condition === "GOOD") {
        공부();
        게임();
        유튜브보기();

        if (weather === "GOOD") {
            운동();
            빨래();
        }

        if (isJob === "GOOD") {
            야간업무();
            조기취침();
        }
    }
}

// early return 적용 후 예시 -2
// 최상위에 거르는 로직을 넣으면, 조건문 간의 의존성을 줄일 수 있다.
const Todo = (condition, weather, isJob) => {
    // early return으로 상위 로직으로부터 하위로직들의 의존성이 줄어들었음
    if (condition !== "GOOD") {
        return
    }

    공부();
    게임();
    유튜브보기();

    if (weather === "GOOD") {
        운동();
        빨래();
    }

    if (isJob === "GOOD") {
        야간업무();
        조기취침();
    }
}

8) 부정조건문 지양하기

  • 부정조건문을 습관적으로 사용하는 경우가 많은데, 아래와 같은 이유로 지양하는 편이 좋다.

    • 이유 1. 생각을 여러번 해야할 수 있다. (예를 들어, isNan과 부정조건문을 함께 사용하는 경우)
    • 이유 2. 프로그래밍 언어 적으로 봤을 때, if문이 처음부터 오고 true부터 실행시키는 구조로 만들어졌다.
    // 부정조건문을 사용한 Bad case
    if (!Number.isNaN(3)) {
        console.log('숫자입니다')
    }
      
    // 부정조건문을 사용한 Good case
    const isNumber = (num) => {
        return !Number.isNan(num) && typeof num === 'number'
    }
      
    if (isNumber(num)) {
        console.log('숫자입니다')
    }
    
  • 반대로 부정조건문을 사용하는 경우도 있다.

    • 경우 1. Early return
    • 경우 2. Form Validation
    • 경우 3. 보안 혹은 검사하는 로직

9) Default Case 고려하기

  • 다수의 parameters를 전달하는 경우, 객체를 사용하게 될 때나 여러 경우에 Default Case를 작성해버릇 하면 아래와 같은 효과를 얻을 수 있다.
    • 효과 1. 사용자의 편의를 위해, 예를 들어 어떠한 값도 넘겨받지 않았을 때 동작하게 한다던지 또는 담당자나 기획자와 소통할 때도 정책과 관련된 기본값을 상의하기에도 좋다.
    • 효과 2. 팀에서 사용하는 코어 라이브러리 개발을 하는 경우에도 유용하다
// bad case - 1
const sum = (x, y) => {
    return x + y
}

// good case - 1
// 사용자가 parameters를 전달하지 않고 호출하더라도 결과를 얻어낼 수 있음
const sum = (x, y) => {
    x = x || 0; 
    y = y || 0; 
    return x + y 
}
// bad case - 2
// 어떠한 html tag가 반함되게 하는 라이브러리 배포 상황
// 이러한 상황에서 사용자는 매번 type, height, width를 넣어줘야 해서 불편하다고 할 수 있음
const createElement = (type, height, width) => {
    const element = document.createElement(type);

    element.style.height = height;
    element.style.width = width;

    return element;
}

// good case - 2
// default 를 작성하여 편의성 개선
const createElement = (type, height, width) => {
    // 개선 1
    const element = document.createElement(type) || 'div';

    // 개선 2
    element.style.height = height || 100;
    element.style.width = width || 100;

    return element;

10) Nullish coalescing operator (Null 병합 연산자)

  • Null 병합 연산자(??)는 Null과 undefined를 평가하는데에만 사용하는 신규 연산자이다.
  • 단, Null 병합 연산자는 실수를 유발할 수 있기 때문에 주의하자.
    • 이유 1. 별 생각없이 ll 를 패스하고 ?? 를 사용할 수 있음
    • 이유 2. null ll undefined ?? false 와 같이 () 없이 병렬로 사용하는 경우, js에서 코더의 실수를 막기위해 처리를 막아두었음
  • 단순예제
const justNull = null;
const justFalsy = 0;

console.log(justFalsy || "Falsy"); // Falsy
console.log(justFalsy ?? "Falsy"); // 0
console.log(justNull || "Falsy"); // Falsy
console.log(justNull ?? "Falsy"); // Falsy
  • 실전 케이스
// Null, undefined 와 나머지 Falsy(0, -0 등)를 구분못하는 경우
const 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;
}

createElement("div>", Null, undefined) // 정상, height, width 크기가 디폴트인 10px 요소가 생성
createElement("<div>", 0, 0) // 에러, height, width 크기가 10px인 요소가 생성

/* ------------------------------------------------------------------------------------------ */

// Null 병합 연산자로 Null, undefined만 구분
const 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;
}

createElement("div>", Null, undefined) // 정상, height, width 크기가 10px인 요소 생성
createElement("<div>", 0, 0) // 정상, height, width 크기가 0px인 요소가 생성

11) 드모르간의 법칙

  • 드모르간의 법칙을 사용하면, 조건문의 논리구성을 비교적 쉽게 읽히도록 사용할 수 있어 유지보수에 좋다. 그리고 드모르간의 법칙을 이용하면, !()형태로 껍데기를 벗겨 이해하기 쉬운 코드로 개선할 수 있다.

true is not true

false is not false

// 드모르간 법칙 적용 전,
const isValidUser1 = true;
const isValidToken1 = true;
if (isValidUser1 && isValidToken1) {
    console.log('로그인 성공!'); // 실행
}
if (!(isValidUser1 && isValidToken1)) {
    console.log('로그인 실패!');
}

const isValidUser2 = true;
const isValidToken2 = false;
if (isValidUser2 && isValidToken2) {
    console.log('로그인 성공!');
}
if (!(isValidUser2 && isValidToken2)) {
    console.log('로그인 실패!'); // 실행
}

const isValidUser3 = true;
const isValidToken3 = false;
if (isValidUser3 || isValidToken3) {
    console.log('로그인 성공!');  // 실행
}
if (!(isValidUser3 || isValidToken3)) {
    console.log('로그인 실패!');
}

const isValidUser4 = false;
const isValidToken4 = false;
if (isValidUser4 || isValidToken4) {
    console.log('로그인 성공!');
}
if (!(isValidUser4 || isValidToken4)) {
    console.log('로그인 실패!'); // 실행
}

  • 드모르간을 사용하여, 아래와 같이 !()형태의 껍대기를 벗겨냄으로써 코드를 이해하고 유지보수하는데 긍정적 효과를 얻을 수 있음.
// 드모르간 적용 후
const isValidUser2 = false;
const isValidToken2 = false;
if (!(isValidUser2 && isValidToken2)) {
    console.log('로그인 실패!'); // 실행
}
// 드모르간의 법칙으로 껍데기()를 벗겨냄
if (!isValidUser2 || !isValidToken2) {
    console.log('로그인 실패!'); // 실행
}

const isValidUser3 = false;
const isValidToken3 = false;
if (!(isValidUser3 || isValidToken3)) {
    console.log('로그인 실패!'); // 실행
}
// 드모르간의 법칙으로 껍데기()를 벗겨냄
if (!isValidUser3 && !isValidToken3) {
    console.log('로그인 실패!'); // 실행
}

다음에 다루게 될 것

  • 배열

댓글남기기