클린코드 자바스크립트 - udemy

Gisele·2022년 4월 28일
2

Javascript

목록 보기
14/14

Udemy의 클린코드 자바스크립트 강의를 보고, 내용을 정리하고, 코드에 적용해본 것을 기록한 글

강의 내용 정리

변수

var의 사용을 지양하자

var의 문제점

  • 중복 선언이 가능하기 때문에, 예기치 못한 값을 반환할 수 있다.
  • 함수 스코프를 가지기 때문에 함수 외부에서 선언한 변수는 모두 전역 변수가 된다.
    -호이스팅이 일어나기 때문에 선언문 이전에 변수를 참조할 수 있고, undefined를 반환한다.

letconst

  • let : 블록 스코프, 선언은 한번, 할당은 여러번, 선언과 할당을 동시에 하지 않아도 된다.
  • const : 블록스코프. 선언과 할당을 동시에 해야하고, 재할당을 할 수 없다. 상수값이라면 const를 사용하는 것을 권장한다.

호이스팅

호이스팅은 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미한다. 변수선언함수선언이 해당 스코프의 최상단으로 끌어 올려진 것 같은 현상을 말한다. 선언을 undefined로 초기화해 코드에서 변수나 함수를 정의하기 전에 해당 변수/함수를 사용할 수 있다.

다만, letconst변수는 호이스팅 시에도 변수를 초기화 하지 않지 않고, 함수 선언이 아닌 함수 표현식은 호이스팅이 일어나지 않는다.

타입

타입검사 : typeof, instaceof

참조형 타입은 typeof로 검사가 어렵다. null도 object로 나온다. 따라서 참조형 타입은 instanceof로 프로토 타입 체인을 확인하는 것이 좋다.

eqeq(==) 대신 eqeqeq(===)

==는 자동으로 형변환이 일어난다. ===은 strinct eqe이므로 값과 자료형을 함께 비교한다.

1=='1' // true
1==='1' // false

isNaN

isNaN()는 넘어오는 인자를 number로 변환을 시도한다.

Number(null) // 0
Number('') // 0
Number('   ')// 0
Number(false) // 0

따라서 null, '',' ',false 등의 값이 0을 반환하므로 아래와 같은 결과가 나온다.

isNaN(null) // false
isNaN('') // false
isNaN('   ')// false
isNaN(false) // false

따라서 숫자 타입 검사를 할 때는 Number.isNaN()으로 검사하는 걸 추천한다. Number.isNaN() 함수는 Numver형에서만 사용가능하고, 강제로 Number 변환을 시도하지 않는다.

Number.isNaN의 함수는 아래와 같다.

Number.isNaN = function(x){
	return typeof x === 'number' && isNaN(x);
}

경계다루기

  • 포함여부(이상, 초과, 미만, 이하)를 나타낼 수 있는 변수를 사용한다.
  • 매개변수 순서가 경계가 될 수 있다.
  • 호출하는 함수의 네이밍과 인자의 순서의 연관성을 고려한다
  • 매개변수를 2개가 넘지 않도록하고, 매개변수를 객체에 담아서 넘긴다.
  • 랩핑하는 함수를 만든다

분기다루기

값식문을 구분하기

  • 리액트의 jsx문 안에는 값과 식만 들어가야한다.
    ex] for문, if문을 넣지않음

truthy와 = 참같은 값, falthy = 거짓같은 값

  • falthy : false null undefined 0 NaN '빈 문자열'

short-circuit evaluation 단축평가

  • and는 모두가 참이어야 도달하고, or는 하나만 참이어도 됨

console.log(true && true && '도달ㅇ') // 도달 ㅇ
console.log(true && false && '도달X') // false

console.log(false || false || 도달) // 도달 d
console.log(true || true || '도달 X') // true
  • 삼항연산자 대신 단축 평가 쓰기, 기본값이 있을 때 쓰면 좋다
function getUserName(user,isLoging){
	if(isLogin && user){
    	return user.name || '이름없음'
         // return user.name? user.name : '이름 없음'
    }
}

else if피하기

  • else if는 if와 else를 처리하고 if를 처리하는 것과 같다. 커버리지가 커지는것보다 조건을 분리하는게 낫다.
  • else if를 계속 쓰는 것보다는 switch문 사용

before😔

      if (data.queue.status === QueueStatusEnum.Done) {
        refetchAllVerificationData();      
      } else if (data.queue.status === QueueStatusEnum.Error) { // 여기!!
        if (retryCount >= 3) {
          setRetryCount(0);         
        } else {
          openUploadRetryNotification({ ...})
        }
}

after😌

      if (data.queue.status === QueueStatusEnum.Done) {
        refetchAllVerificationData();       
        return;
      }

      if (data.queue.status === QueueStatusEnum.Error) {
        if (retryCount >= 3) {         
          setRetryCount(0);
          completeUploadMutation();
          useNotification(
            'error',
            t('notification.settlement.failUploadFile'),
            t('common.notification.contactManager')
          );
          return; // early return으로 처리
        }
    
        openUploadRetryNotification({...});
      }

else피하기

  • else는 단축 평가문으로 대체 가능하다.

early return

함수를 미리 종료하는 것을 의미한다. if-else가 많거나 중첩되는 것보다 이해하기 편한 코드를 작성할 수 있다.

before😔

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

after😌

function loginServer(isLogin, user){
	if(isLogin) return;
  
  	if(!checkToken()) throw new Error('no Token')
  
  	if(!user.nickName) return registerUser(user);
  
  	refreshToken();
  
  	return '로그인 성공'
  
}

부정 조건문 지양하기

  • if(!isNaN) 같은 표현은 헷갈린다.
  • early return이나 form validation을 사용할 때는 예외적으로 사용한다.

Default Case 고려하기

default case를 고려하면 안전하고 확정성 높은 코드를 작성할 수 있다. 엣지 케이스를 고려해 디폴트 값을 넣자.

case 1. 매개변수를 넣지 않았을 때

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

sum() // 매개변수를 넣지않았을 때

case 2. switch-case 문에서

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

Nullish coalescing operator (널 병합 연산자 ??)

  • ?? : 왼쪽 피연산자가 null 또는 undefined일 때 오른쪽 피연산자를 반환하고, 그렇지 않으면 왼쪽 피연산자를 반환하는 논리 연산자
  • || : null, undefined뿐 아니라 falsy 값에 해당할 경우 오른쪽 피연산자를 반환한다.

드모르간 법칙

!(A || B) = !A && B!

조건이 추가될 때는 드모르간의 법칙을 쓰는 것이 직관적이다.

배열

javascript 배열은 객체다

	const arr = [1, 2, 3];

	const obj = {
    	0: 1,
      	1: 2,
      	2: 3
    }    
    

Array.length

  • length는 배열의 길이, 즉 마지막 인덱스다
	arr[10] = 4;

	console.log(arr.length) // 10
	console.log(arr) // [1,2,3,...,4]

배열요소에 접근할 때는 구조분해 할당을 이용

const btob = ['서은광, '이민혁', '이창섭', '임현식', '프니엘', '육성재']
              
const [a,b,...rest] = btob;

console.log(a) // 서은광
console.log(b) // 이민혁

유사 배열 객체

  • Array.from(object) : 유사 배열 객체나 반복 가능한 객체를 얕게 복사해 새로운 Array 객체를 만든다.
const arrayLikeObject = {
	0:'Hello',
  	1 : 'World',
  	length : 2
}

const arr = Array.from(arrayLikeObject);

console.log(Array.isArray(arrayLikeObject))) // false
console.log(Array.isArray(arr))) // true
  • argument : 함수의 매개변수를 따로 선언하지 않아도 arguments를 사용할 수 있다. 하지만 유사배열 객체이므로 배열 메서드를 사용할 수 없다.
function haha(){
	console.log(argument) // 1,2,3
}

haha(1,2,3)

불변성(immutable)

  • 배열은 참조형 자료형이므로 변수에 담았을 때 원본 배열의 영향을 받는다.
  • 불변성을 지키는 법 : 배열복사, 새로운 배열을 반환하는 메서드를 사용한다
    - 새로운 배열을 반환하는 메서드 : filter, map, ...
    • push, unshift 등은 원본배열을 바꾼다

for문을 배열 고차 함수로 리팩터링하기

불필요한 임시변수를 사용하지 않게 되고, 명확하고 선언적으로 코드를 작성할 수 있다.

break와 continue

반복문을 제어한다. for문에서는 동작하지만 배열 메서드에서는 동작하지 않는다. 흐름을 제어하고 싶을 때는 for문을 사용하되 for of, for in을 사용하면 좀 더 편하게 사용할 수 있다.

객체

단축속성 shorthand property

const firstName = 'yoon'
const lastName = 'jo'

const person = {
	firstName : 'yoon',
    lastName : 'jo',
  	getFullName : function(){
  		return this.firstName + ' ' + this.lastName;
  	}
}

const shortHandPerson = {
	firstName,
  	lastName,
  	getFullName(){ // 메서드도 축약이 가능하다
    	return this.firstName + ' ' + this.lastName;
    }
}

conputed property name

객체의 key로 []를 사용해 계산된 값을 넣을 수 있다.

const key  = color;

const banana = {
	krName : '바나나',
    [key] : 'yellow'  
}

console.log(banana) //{krName:'바나나', color:'yellow'}

lookup table

key와 value를 이용해 switch-case문이나 조건문을 객체로 처리가능 하다.

before😔

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

after😌

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

Object.freeze

객체를 동결하는 함수다. 재할당해도 원본을 유지하고, 값을 추가해도 동결한다. 단, 객체 안의 객체까지는 동작을 안하므로 중첩된 freeze 함수를 사용해야 한다.

객체에 직접 접근 지양하기

객체에 직접 접근하기 보다 대신 없근하는 함수를 만들어 레이어를 분리하는 것이 좋다.

before😔

const model = {
	isLogin : false,
  	isValidToken : false
}

function login(){
	model.isLogin = true;
  	model.isValidToken = true;
}

function logout(){
	model.isLogin = false;
  	model.isValidToken = false;
}

after😌

const model = {
	isLogin : false,
  	isValidToken : false
}

function setLogin(value){
	model.isLogin = value
}

function setIsValidToken(value){
	model.isValidToken = value;
}

function login(){
	setLogin(true)
  	setIsValidToken(true)
}

function logout(){
	setLogin(false)
  	setIsValidToken(false)
}

함수

자바스크립트의 함수는 일급객체다.
1. 변수나 데이터에 담길 수 있다.
2. 매개 변수로 전달가능하다.
3. 함수가 함수를 반환할 수 있다.

  • 메서드란 객체에 의존성이 있는 함수다. OOP 행동을 의미한다.

복잡한 인자 관리하기

매개변수를 보고 맥락을 유추할 수 있도록 작성해야 한다. 맥락유추가 어렵고 매개변수가 많은 경우 객체로 매개변수를 전달하는 것이 좋다.

void와 return

javascript 함수는 기본적으로 undefined를 리턴한다. 반환값이 없을 때 습관적으로 return 뒤에 값을 넣지 말것. early return 할 때도 반환값이 없으면 return;만해도 된다.

before😔

function handleClick(){
	return setState(false)
}

after😌

function handleClick(){
	setState(false)
}

콜백함수

콜백함수는 다른 함수로 넘겨서 제어권을 위임할 수 있다.

회고

통근 시간 지하철에서 듣기에 여러모로 적합한 강의였고, 당장 코드에 적용할 수 있는 실용적인 내용이 많았으며, javascript의 개념들을 한번 더 정리하면서 갈 수 있었다.

늘 고민이었던 if-else문 사용에 힌트를 얻을 수 있었고, 이번 스프린트를 진행하면서 for문으로 좀 더 편하게 작성할 수 있는 코드를 forEach를 굳이 사용하려고 해 오래 헤맸는데, 둘 중 무조건 써야한다는 것 없이 상황에 적합한 것을 쓰는 것이 좋다는 당연한 사실을 배웠다. 그리고 switch-case문 대신 lookup table을 사용할 때 input value와 key가 없을 때 처리하는 방법을 잘 몰랐는데, undefined default 값을 줄 수 있다는 것을 배웠다. 또 default 값을 위해 삼항연산자로 처리하던 코드를 단축평가로 수정했다.


profile
한약은 거들뿐

0개의 댓글