[JavaScript] 클린코드 참고자료 - 1 (변수, 배열)
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://blog.makerjun.com/195df3cd-670b-473c-a769-de7bb8ce9c30