티스토리 뷰
※ 출처: https://www.udemy.com/course/clean-code-js/
- 총 섹션 13으로 이루어져 있고 22년 01월 기준 섹션 8까지 올라와 있음.
- 나머지 강의 아직 안 올라와서 나중에 듣고 업데이트 하기.
- 앞에 부분은 이전에 들어서 제목만 적음.
- 01-01 :: ~5장, 26강 early return
- 01-02 :: ~ 8장, 57강 화살표 함수
- 01-06 :: ~ 8장, 60강 Closure
- 이곳저곳에서 다 듣거나 본 내용이라 어렵진 않아 2배속으로 봤는데 막상 적용 시키지 않는 것도 좀 있는듯..
- 계속 의식하고 적용시키려고 해야할 듯.
2장: 변수 다루기
- var 지양하기
- function scope & block scope
- 전역 공간 사용 최소화
- 임시변수 제거하기
- 호이스팅 주의하기
3장: 타입 다루기
- 타입 검사
- undefined & null
- eqeq 줄이기
- 형변환 주의하기
- isNaN
4장: 경계 다루기
- min - max
- begin - end
- first - last
- prefix - suffix
- 매개변수의 순서가 경계다.
5장: 분기 다루기
- 값식문
- 삼항 연산자 다루기
- Truthy & Falsy
- 단축평가
- 부정조건문 지양하기
- 코드를 좀 더 명시적이게 작성하기 위함.
- 생각을 한번 더 해야한다 → 실수 확률 높음.
- if 문이 처음부터 오고 true 부터 실행시킨다.
- 그럼 언제?
- early return
- form validation
- 보안 혹은 검사 로직
// 부정조건문 지양하기
if (!isCondition) {
console.log('거짓인 경우만 실행');
}
if (isNotCondition) {
console.log('거짓인 경우만 실행');
}
- Default Case 고려하기
- edge case 를 고려하자.
- ex) 함수의 인자가 안들어오거나 잘못들어오거나 이런경우 고려하자.
- 대부분의 라이브러리나 언어에서 default 값 설정을 중요시하게 여김.
- 유저의 실수를 대비
function safeParseInt(number, radix) {
return parseInt(number, radix || 10);
}
- 명시적인 연산자 사용 지양하기
- 연산자 우선순위를 생각해서 작성 하지말고 () 와 같은 걸 써서 좀 더 명시적이게 작성하자.
- 예측 가능하고 누가봐도 읽기 쉽고 디버깅 하기 쉬운...
- Nullish coalescing operator
- null 과 undefined 를 평가할때만 사용해야 한다!
function createElement1(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;
}
function createElement2(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;
}
// width, height 가 0인 element 를 생성하고 싶음.
const el = createElement1(span, 0, 0);
console.log(el.style.height) = '10px'; // ???
const el = createElement2(span, 0, 0);
console.log(el.style.height) = '0px'; // good
- createElement1 의 경우 0은 falsy 값으로 인식되어 기본값 10이 들어가버림.
- createElement2 의 ?? 연산자는 좌항이 null 이거나 undefined 일 경우만 우항의 값을 대입함.
// No chaining with AND or OR operators
// syntax error
null || undefined ?? 'foo';
// good
(null || undefined) ?? 'foo';
- 드모르간의 법칙
if (isValidToken && isValidUser) {
console.log('로그인 성공');
}
// bad - 감싸서 부정연산자를 넣는건 더 복잡해지고 헷갈린다.
// 뒤에 연산이 더 추가된다면 복잡해짐.
if (!(isValidToken && isValidUser)) {
console.log('로그인 실패');
}
// good - 좀 더 간단해짐
if (!isValidToken || !isValidUser) {
console.log('로그인 실패');
}
6장: 배열 다루기
- JavaScript의 배열은 객체다.
// 배열인지 체크하고 싶을때 이렇게 사용 추천
Array.isArray(arr);
- Array.length
- Array.length 가 배열의 길이를 보장하진 않음. 그냥 마지막 인덱스라고 봐야함.
- JS 에서 배열의 length 는 의식적으로 주의해서 사용하자.
// Array.length 이용하기
Array.property.clear = function() {
this.length = 0;
}
function clearArray(array) {
array.length = 0;
return array;
}
const arr = [1, 2, 3];
//
arr.clear();
console.log(arr); // []
console.log(clearArray(arr)); // []
- 배열 요소에 접근하기
// ex1) bad - 배열[num] 이런식으로 직접 접근하는건 어떤 값인지 명확하지 않음.
function operateTime(input, operators, is) {
inputs[0].split('').forEach((num) => {
.... logic
});
inputs[1].split('').forEach((num) => {
.... logic
});
}
// ex1) good1 - 구조분해할당을 사용해서 접근 (명시적)
function operateTime(input, operators, is) {
const [firstInput, secondInput] = inputs;
firstInput.split('').forEach((num) => {
.... logic
});
secondInput.split('').forEach((num) => {
.... logic
});
}
// ex1) good2 - 받을때부터 분해해서 받기
function operateTime([firstInput, secondInput], operators, is) {
firstInput.split('').forEach((num) => {
.... logic
});
secondInput.split('').forEach((num) => {
.... logic
});
}
// ex2) bad - 직접 접근은 이게 뭐하는애인지 모름.
function formatDate(targetDate) {
const date = targetDate.toISOString().split('T')[0];
... logic
}
// ex2) good1 - 배열에 하나만 들어있어도 구조분해할당 가능
function formatDate(targetDate) {
const [date] = targetDate.toISOString().split('T');
... logic
}
// ex2) good2 - 유틸함수 만들어 사용
function head(arr) {
return arr[0] ?? '';
}
function formatDate(targetDate) {
const date = head(targetDate.toISOString().split('T'));
... logic
}
- 유사 배열 객체
function generatePriceList() {
// arguments는 배열이 아님
// arguments.map is not a function
console.log(Array.isArray(arguments)); // false
1. return arguments.map((arg) => arg + '원');
// map 을 사용하고싶으면 Array.from 으로 배열로 바꿔서 사용해야함
2. return Array.from(arguments.map((arg) => arg + '원'));
}
generatePriceList(100, 200, 300, 400, 500);
- 불변성
- 배열을 복사한다.
- 새로운 배열을 반환하는 메서드들을 활용한다.
- Array.filter(), map(), slice() ...
- for 문 배열 고차 함수로 리팩터링
- for 문 대신 배열의 고차 함수를 사용하자.
- 배열 메서드 체이닝 활용하기
// 이런식으로 메서드 체이닝 활용 가능
function getWonPrice(priceList) {
return priceList
.filter(isOverOneThousand)
.sort(ascendingList)
.map(suffixWon);
}
- map vs forEach
- return 이 있는가 없는가
- continue vs break
- 고차함수 안에서 break, continue 는 syntax error 임
- 사용하고 싶을땐 try catch 이나 차라리 for 문 사용
- every, some, find, findIndex() 를 사용하여 반복을 종료할 수 있음.
7장: 객체 다루기
- Shorthand Properties
const firstName = 'subin';
const lastName = 'lee';
const name = someFunction({
firstName,
lastName,
});
- Computed Property Name
// ex
const handleChange = (e) => {
setState({
[e.target.name]: e.target.value,
});
}
- Lookup Table (순람표)
// bad - 새로운 조건이 추가될때마다 쭉 늘어남
function getUserType(type) {
switch (key) {
case 'ADMIN':
return '관리자';
break;
case 'INSTRUCTOR':
return '강사'
break;
default:
return '해당없음';
}
}
// good - 객체, computed property 활용
function getUserType(type) {
// ex1 - 객체 사용
const USER_TYPE = {
ADMIN: '관리자',
INSTRUCTOR: '강사',
STUDENT: '학생',
UNDEFINED: '해당 없음',
}
// 1
return USER_TYPE[type] ?? '해당 없음';
// 2
return USER_TYPE[type] ?? USER_TYPE.UNDEFINED;
// ex2 - 바로 리턴, ex1 방법을 더 권장함.
return (
{
ADMIN: '관리자',
INSTRUCTOR: '강사',
STUDENT: '학생',
}[type] ?? '해당 없음';
)
}
- Object Destructuring
// ex1 - 인자의 순서를 지켜야함.
function Person(name, age, location) {
this.name = name;
this.age = age;
this.location = location;
}
const subin = new Person('subin', 29, 'korea');
// ex2 - 구조분해할당 - 인자 순서 안지켜도됨.
// 인자가 3개 이상일때 이런식으로 하는걸 추천함.
function Person({ name, age, location }) {
this.name = name;
this.age = age ?? 30;
this.location = location ?? 'korea';
}
const subin = new Person({
name: 'subin',
age: 29,
location: 'korea',
});
// ex3 - 필수적인 값을 받고싶을때
function Person(name, { age, location }) {
this.name = name;
this.age = age;
this.location = location;
}
const options = {
age: 29,
location: 'korea',
}
const subin = new Person('subin', options);
- Object.freeze
- 대중적인 유틸 라이브러리 (lodash) 사용
- 직접 유틸 함수 생성 (deepFreeze 처럼)
- TS 사용 ⇒ readonly
// Object.freeze -> 변화 불가하게 만듬
const STATUS = Object.freeze({
PENDING: 'PENDING',
SUCCESS: 'SUCCESS',
FAIL: 'FAIL',
OPTIONS: {
GREEN: 'GREEN',
RED: 'RED',
},
});
STATUS.PENDING = 'P2'; // 변화 X
STATUS.KING = 'KING'; // 추가도 안됨
console.log(STATUS.PENDING); // PENDING
Object.isFrozen(STATUS.PENDING); // true
// 깊은 freezing 안됨.
Object.isFrozen(STATUS.OPTIONS); // false
STATUS.OPTIONS.GREEN = 'G';
STATUS.OPTIONS.YELLOW = 'YELLOW';
console.log(STATUS.OPTIONS.GREEN); // G
console.log(STATUS.OPTIONS.YELLOW); // YELLOW
- Prototype 조작 지양하기
- 이미 JS는 많이 발전했다.
- 직접 만들어서 모듈화
- JS 빌트인 객체를 함부로 건들지 말자.
- 다른 라이브러리들도 프로토타입을 건들진 않음.
- hasOwnProperty
// ex1.
const person = {
name: 'subin',
}
person.hasOwnProperty('name'); // true
person.hasOwnProperty('age'); // false
// ex2. 예약어 보호를 받지 못함
// -> Object.prototype.hasOwnPrototype.call() 이런식으로 사용
const foo = {
hasOwnProperty: function() {
return 'hasOwnProperty';
},
bar: 'string',
};
foo.hasOwnProperty('bar') // hasOwnProperty
Object.prototype.hasOwnProperty.call(foo, 'bar') // true
// ex3. 유틸로 만들기
function hasOwnProp(targetObj, targetProp) {
return Object.prototype.hasOwnProperty.call(
targetObj,
targetProp,
);
}
- 직접 접근 지양하기
- 예측 가능한 코드를 작성해 동작이 예측 가능하게 하자.
- 데이터에 접근할때는 항상 안전하게 접근하자.
- 괜히 setter, getter 를 사용하는게 아니다.
- Optional Chaining
- Extends & Mixin
8장: 함수 다루기
- 함수, 메서드, 생성자
- 함수, 메서드, 생성자를 구분할 수 있고 어쩔때 사용하는지 알아야한다.
- argument & parameter
- Parameter (Formal Parameter)
- Argument (Actual Parameter)
function example(parameter) {
console.log(parameter);
}
const argument = 'foo';
example(argument);
- 복잡한 인자 관리하기
- 무조건 인자가 3개 이상이라고 나쁜것은 아니다. 맥락이 중요하다.
- 객체 구조분해할당 사용하면 좋다.
- 다른사람이 이 함수를 사용해도 문제 없게 명시적으로 작성.
- Default value, Default parameter
// ex1
function createCarousel({
margin = 0,
center = false,
navElement = 'div',
} = {}) {
... logic
return {
margin,
center,
navElement,
};
}
createCarousel(); // {margin = 0, center = false, navElement = 'div'}
// ex2. 필수로 받아야하는 인자 설정
const required = (argName) => { throw new Error(`required ${argName}`) };
function createCarousel({
items = required('items'),
margin = 0,
center = false,
navElement = 'div',
} = {}) {
... logic
return {
margin,
center,
navElement,
};
}
- Rest Parameters
- 인자의 가장 마지막에 들어와야함.
- 배열로 들어옴.
function sumTotal(initValue, bonusValue, ...args) {
console.log(initValue); // 100
console.log(bonusValue); // 99
Array.isArray(args); // true
return args.reduce((acc, cur) => acc + cur);
}
sumTotal(100, 99, 1, 2, 3, 4, 5, 6, 7, 8);
- void & return
- void function 에 불필요하게 return 을 해줄 필요가 없음.
- API 명세를 잘 읽어서 return 값이 무엇인지 알 필요가 있음.
- 함수명으로 반환값을 유추할 수도 있으니 네이밍을 잘하자.
- 화살표 함수
- 내부에서 arguments, call, apply, bind 함수 사용 안됨.
- this 주의해야함.
- 생성자로 사용할 수 없음.
- 클래스의 메소드로 사용할때 예외가 많음.
- Callback Function
- 제어권을 위임하는 것.
- 무조건 나쁘다? 잘못 이해하는 것임.
- 순수 함수
- side effect를 일으키지 않는 함수
- 예측이 가능한..
- input이 동일하면 output도 동일해야지.
let num1 = 10;
let num2 = 20;
function impureSum() {
return num1 + num2;
}
function puerSum(num1, num2) {
return num1 + num2;
}
// 객체, 배열 => 새롭게 만들어서 리턴
function changeObj(targetObj) {
// targetObj.num = 100;
return { ...targetObj, num: 100 };
}
- Closure
- 어색해서 그런지 읽히는게 직관적이지 않음.
- 어디에 어떻게 써먹을까 했는데 잘쓰면 엄청 유용해보임.
- 쓰려고 연습해야할듯.
// ex.1
function add(num1) {
return function sum(num2) {
return num1 + num2;
}
}
const addOne = add(1); // function
const addTwo = add(2); // function
const addThree = add(1)(2) // 3
// ex.2
function add(num1) {
return function (num2) {
return function (calculateFn) {
return calculateFn(num1, num2);
}
}
}
function sum(num1, num2) {
return num1 + num2;
}
function multiple(num1, num2) {
return num1 * num2;
}
const addOne = add(5)(2); // function
const sumAdd = addOne(sum); // 7
const sumMultiple = addOne(multiple); // 10
// ex.3
function log(value) {
return function(fn) {
fn(value);
}
}
const logFoo = log('foo');
logFoo((v) => console.log(v));
logFoo((v) => console.info(v));
logFoo((v) => console.error(v));
logFoo((v) => console.warn(v));
// ex.4
const arr = [1, 2, 3, 'A', 'B', 'C'];
// 4-1
const isNumber = (value) => typeof value === 'number';
const isString = (value) => typeof value === 'string';
// 4-2
function isTypeOf(type) {
return typeof value === type;
}
const isNumber = (value) => isTypeof('number');
const isString = (value) => isTypeof('string');
// 4-3
function isTypeOf(type) {
return function (value) {
return typeof value === type;
}
}
const isNumber = isTypeOf('number');
const isString = isTypeOf('string');
arr.filter(isNumber);
arr.filter(isString);
// ex.5
function fetcher(endpoint) {
return function (url, options) {
return fetch(endpoint + url, options)
.then((res) => {
if (res.ok) {
return res.json();
} else {
return new Error(res.error);
}
})
.catch((err) => console.err(err));
}
}
const naverApi = fetcher('http://naver.com');
const daumApi = fetcher('http://daum.net');
naverApi('/webtoon').then((res) => res);
daumApi('/webtoon').then((res) => res);
// ex.6
9장: 추상화하기
10장: 에러 다루기
11장: Browser & Web API
12장: 도구에 위임하기
13장: 함께하기
반응형
'JavaScript & TypeScript' 카테고리의 다른 글
fastify-multipart handle multiple file streams and fields in TypeScript (2) | 2022.09.22 |
---|---|
브라우저, JS 흐름 정리 메모 (2) | 2022.05.22 |
Next export 시 Image Optimization 설정 문제 (3) | 2022.01.03 |
TypeORM synchronize true 시 이전 table 까지 생성 문제 (2) | 2021.12.26 |
axios (0) | 2020.12.13 |
링크
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- 프로그래머스 SQL
- 킹수빈닷컴
- JS 딥다이브
- HTTP 완벽 가이드
- HTTP 완벽가이드
- BOJ
- http
- JPA 연관관계 매핑
- 이펙티브자바 아이템59
- REST API
- 패스트캠퍼스 컴퓨터공학 완주반
- js promise
- dreamcoding
- 이펙티브자바 아이템60
- 모던자바스크립트
- 가상 면접 사례로 배우는 대규모 시스템 설계 기초
- 이펙티브자바
- js api
- Spring Security
- 드림코딩
- 백기선 스터디
- java
- GCP
- 프로그래머스
- 김영한 JPA
- 김영한 http
- 집 구하기
- 백준
- js array
- 이펙티브자바 스터디
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
글 보관함