개발/JavaScript

[JavaScript] 클린코드 참고자료 - 1 (변수, 배열)

개발자 솜 2022. 4. 25. 15:44
Udemy 클린코드 강의를 수강하고 내가 지키지 않고 있거나 익숙해 져야 할 것들 정리

변수

타입 검사

console.log(Object.prototype.toString.call("")); // [object String]
console.log(Object.prototype.toString.call(new String(""))); // [object String]
console.log(Object.prototype.toString.call(arr)); // [object Array]
console.log(Object.prototype.toString.call(func)); // [object Function]
console.log(Object.prototype.toString.call(date)); // [object Date]

Logical NOT (!)

논리 NOT (!) 에서 false가 되는 것들

  • null
  • NaN
  • 0
  • 빈 문자열("", '', ``)
  • undefined

Reference : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT

 

Logical NOT (!) - JavaScript | MDN

The logical NOT (!) operator (logical complement, negation) takes truth to falsity and vice versa. It is typically used with boolean (logical) values. When used with non-Boolean values, it returns false if its single operand can be converted to true; other

developer.mozilla.org

 

임시 변수 제거하기

 

BAD

function getElement() {
  const result = {}; // 임시 객체
  result.title = document.querySelector(".title");
  result.text = document.querySelector(".text");
  result.value = document.querySelector(".value");

  return result;
}

 

GOOD

function getElement() {
  result = {
    title: document.querySelector(".title"),
    text: document.querySelector(".text"),
    value: document.querySelector(".value"),
  };
}

 

 

이 경우 추가 요구사항이 들어올 경우, getDateTime()를 변환하는 대신 리턴한 후 새로운 함수를 호출하는 편이 깔끔하다.

getDateTime()이 다른데서 사용될 수도 있고 길어지면 보기 힘들어지기 때문이다.

 

BAD

function getDateTime(targetDate) {
  let month = targetDate.getMonth();
  let day = targetDate.getDay();
  let hour = targetDate.getHour();

  month = month >= 10 ? month : "0" + month;
  day = day >= 10 ? day : "0" + day;
  hour = hour >= 10 ? hour : "0" + hour;

  return {
    month,
    day,
    hour,
  };
}

 

GOOD

// return에 바로 변수를 담음으로써 임시변수 줄이기
function getDateTime(targetDate) {
  const month = targetDate.getMonth();
  const day = targetDate.getDay();
  const hour = targetDate.getHour();

  return {
    month: month >= 10 ? month : "0" + month,
    day: day >= 10 ? day : "0" + day,
    hour: hour >= 10 ? hour : "0" + hour,
  };
}

// 요구사항 함수 추가
function currentDateTime() {
  const currentDateTime = getDateTime(new Date());

  return {
    month: currentDateTime.month + "분 전",
    day: currentDateTime.day + "분 전",
    hour: currentDateTime.hour + "분 전",
  };
}

분기

단축 평가 값 (short-circuit-evaluation)

AND

True면 다음 실행, 다음이 없다면 반환

False면 false 반환 

console.log(true && true && "도달 O"); // 도달O
console.log(true && false && "도달 X"); // false

OR

True면 반환

False면 다음 실행, 다음이 없다면 반환

console.log(false || false || "도달 O"); // 도달 O
console.log(true || true || "도달 X"); // true

 

BAD

function favoriteDog(someDog) {
  let favoriteDog;
  if (someDog) {
    if (someDog) {
      favoriteDog = dog;
    } else {
      favoriteDog = "냐옹";
    }
  }
  return favoriteDog;
}

 

GOOD

function favoriteDog(someDog) {
  return someDog || "나옹";
}

 

BAD

const getActiveUserName = (user, isLogin) => {
  if (isLogin) {
    if (user) {
      if (user.name) {
        return user.name;
      } else {
        return "이름 없음";
      }
    }
  }
};

 

GOOD

const getActiveUserName = (user, isLogin) => {
  if (isLogin && user) {
    return user.name || "이름없음";
  }
};

 

Early Return 

타인이 보기 편한 코드 작성하기

 

BAD

function loginService(isLogin, user) {
  if (!isLogin) {
    if (checkToken()) {
      if (!user.nickName) {
        return registerUser(user);
      } else {
        refreshToken();
        return "로그인 성공";
      }
    } else {
      throw new Error("No Token");
    }
  }
}

 

GOOD

function loginService(isLogin, user) {
  if (isLogin) return;

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

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

  refreshToken();
  return "로그인 성공";
}

 

BAD

function 오늘하루(condition, weather, isJob) {
  if (condition === "GOOD") {
    공부();
    게임();
    유투브보기();

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

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

 

GOOD

function 오늘하루(condition, weather, isJob) {
  if (condition !== "GOOD") return;
  공부();
  게임();
  유투브보기();

  if (weather !== "GOOD") return;
  운동();
  빨래();

  if (isJob !== "GOOD") return;
  야간업무();
  조기취짐();
}
 
예측가능하고 디버깅 하기 쉬운 코드 만들기
괄호를 이용해 우선순위를 직관적으로 알 수 있게 구현하기
 

GOOD

if ((isLogin && token) || user) {...}

전위 연산자, 후위 연산자 사용 자제하기

function increment() {
  // BAD
  number++;
  ++number;
  // GOOD
  number += 1;
}

배열

 

배열 요소에 접근할때 [0] [1] 이런식으로 인덱스값으로 접근 지양하기

 

BAD

function operatorTime(input, operators, is) {
  input[0].split("").forEach((num) => {});
  input[1].split("").forEach((num) => {});
}

 

GOOD

function operatorTime(input, operators, is) {
  const [firstInput, secondInput] = inputs;
  
  firstInput.split("").forEach((num) => {});
  secondInput.split("").forEach((num) => {});
}

 

유사 배열 객체

const obj = {
  0: "Hello",
  1: "World",
  length: 2,
};
console.log(obj); // {"0":"Hello","1":"World","length":2}
const arr = Array.from(obj);
console.log(arr); // ["Hello","World"]

const arr2 = arr.map((element) => element + "!");
console.log(arr2); // ["Hello!","World!"]

 

메서드 체이닝

const isOverOneThousand = (price) => Number(price) > 1000;
const ascendingList = (a, b) => a - b;
const suffixWon = (price) => price + "원";

function getWonPrice(priceList) {
  return priceList.filter(isOverOneThousand).sort(ascendingList).map(suffixWon);
}

const result = getWonPrice(price);

 

map vs forEach

map은 반환값이 있지만 forEach는 반환값이 없다.

map은 원본 배열을 변환시키지 않지만 forEach는 변환시킨다.

const prices = ["1000", "2000", "3000"];

const newPricesForEach = prices.forEach(function (price) {
  return price + "원";
});

const newPricesMap = prices.map(function (price) {
  return price + "원";
});

newPricesForEach; // undefined - map은 반환값이 없다
newPricesMap; // ['1000원', '2000원', '3000원']

객체

 

Shorthand property

// 적용 전
const counterApp = combineReducers({
  counter: counter,
  extra: extra,
  counter2: counter2,
  counter3: counter3,
});

// 적용 후 
const counterApp = combineReducers({
  counter,
  extra,
  counter2,
  counter3,
});

Concise Method

// 적용 전
const person = {
  firstName: "poco",
  lastName: "jang",
  getFullName: function () {
    return this.firstName + " " + this.lastName;
  },
};

// 적용 후
const person2 = {
  firstName: "Bob",
  lastName: "Yun",
  getFullName() {
    return this.firstName + " " + this.lastName;
  },
};

Computed property name

const funcName = 'func';

const obj = {
	[funcName]() {
		return 'func';
	},
};

console.log(obj[funcName]()); // func

Object Lookup table

BAD

function getUsetType(type) {
  switch (key) {
    case "ADMIN":
      return "관리자";
    case "INSTRUCTOR":
      return "강사";
    case "STUDENT":
      return "학생";
    default:
      return "해당 없음";
  }
}

 

GOOD

function getUsetType(type) {
  const USER_TYPE = {
    ADMIN: "관리자",
    INSTRUCTOR: "강사",
    STUDENT: "수강생",
  };
  
  return USER_TYPE[type] || "해당 없음";
}

Object Destructuring (구조 분해 할당)

 

BAD

function Person(name, age, location) {
  this.name = name;
  this.age = age;
  this.location = location;
}
const bob = new Person("Bob", 30, "korea");

 

GOOD

function Person({ name, age, location }) { 
  this.name = name;
  this.age = age;
  this.location = location;
}
// 호출부에서 파라미터의 순서를 지키지 않아도 된다.
const bob = new Person({
  name: "Bob",
  age: 30,
  location: "korea",
});

 

어떤 파라미터를 필수로 받아야 할 때

BAD (lagacy)

function Person(name, options) {
  this.name = name;
  this.age = options.age;
  this.location = options.location;
}

const options = {
  age: 30,
  location: "korea",
};

const bob = new Person("Bob", options);

 

GOOD

function Person(name, { age, location }) {
  this.name = name;
  this.age = age;
  this.location = location;
}

const option = {
  age: 30,
  location: "korea",
};

const bob = new Person("Bob", option);

 

BAD

cosnt orders = ["First", "Second", "Third"];
const [first , , third] = orders;

console.log(first); 
console.log(third);

 

GOOD

const orders = ["First", "Second", "Third"];
const { 0: st, 2: th } = orders;

console.log(st); // first
console.log(th); // third

 

Reference 

https://www.udemy.com/share/105eG63@HB7IorwPDrjFzMMb77SIxqGRBSbAnLDcQXrvSpuq1Zd3GbDY-oUkXNpLhbZHPhed/

https://blog.makerjun.com/195df3cd-670b-473c-a769-de7bb8ce9c30