클린코드

박찬영·2024년 2월 10일
0
post-thumbnail
  1. 프론트엔드 개발자이기 때문에 사용자의 실수를 예방하자.
  2. if , else if 문이 너무 길어질 경우 switch case 문을 고려해보자.

Truthy & Falsy

❌⭕

❌❌❌
if(a.length > 0) {...}
if(!isNaN(10)) {...}
if(boolean === true) {...}
if(name === undefined || name === null) {...}

⭕⭕⭕
if(a.length) {...}
if(10) {...}
if(boolean) {...}
if(name) {...}

단축 평가

❌❌❌
const data = state.data ? state.data : 'Fetching...';

⭕⭕⭕
const data = state.data || 'Fetching...';

❌❌❌
const getUser(user, isLogin) {
	if(isLogin) {
    	if(user) {
        	if(user.name) {
            	return user.name
            } else {
            	return '이름 없음'
            }
        }
    }
}

⭕⭕⭕
const getUser(user, isLogin) {
	if(user && isLogin) {
    	return user.name || '이름 없음'
    }
}

Early return

❌❌❌
const loginService = (isLogin, user) => {
	if(!isLogin) {
    	if(!user) {
          if(!userToken) {
          	....
          }
        }
    }
}

⭕⭕⭕
const loginService = (isLogin, user) => {
	if(isLogin) {
      return
    }
  
  	if(user) {
      return
    }
  
    if(userToken) {
      return
    }
}

// 사람이 사고하기 좋은 코드

부정조건문 지양하기

❌❌❌
if(!isNaN(num)) {
	console.log('숫자 입니다.')
}

⭕⭕⭕
const isNumber(num) {
	return !Number.isNaN(num) && typeof num === 'number';
}

if(isNumber(num)) {
	console.log('숫자 입니다.')
}

딱 봐도 가독성이 좋아보이고 헷갈리지 않는다.


배열 다루기

배열 요소 접근하기

//배열 요소 접근할 때 구조분해를 하는것을 추천
❌❌❌
const arr = [1,2,3,4 ...];
const a = arr[0];
const b = arr[1];

⭕⭕⭕
const arr = [1,2,3,4 ...];
const [a,b] = arr;

고차함수와 메서드 체이닝 활용하기

forEach vs Map

forEach 와 Map 의 다른점은 return 이다.
forEach 는 단순히 함수를 실행해주고 map 은 함수를 실행해서 배열에 넣어준다.
map 은 또한 새로운 배열을 반환해주기 때문에 불변성을 지켜줄 수 있다.

const prices = [1000, 2000, 3000];

const getPricesForEach = prices.forEach(item => return item + '원')
const getPricesMap = prices.Map(item => return item + '원')

console.log(getPricesForEach())    // undefined
console.log(getPricesMap())		   // ['1000원', '2000원', '3000원']

continue, break 오류

자바스크립트에서 고차 함수 내에서 if 문에서 break나 continue를 사용하면 오류가 발생하는 이유는, break와 continue는 반복문(for, while 등)에서만 유효하기 때문입니다.

고차 함수는 다른 함수를 인자로 받거나 함수를 반환하는 함수를 말합니다

예를 들어, 다음과 같은 고차 함수가 있다고 가정해봅시다:

function customForEach(arr, callback) {
  for (let i = 0; i < arr.length; i++) {
    if (callback(arr[i], i, arr) === 'something') {
      break; // 오류 발생
    }
  }
}

위의 코드에서 break 문은 반복문이 아닌 고차 함수 내에서 사용되고 있으므로 오류가 발생합니다.

대신, 배열을 순회하며 특정 조건을 만족하는 요소를 찾거나 특정 작업을 수행하려면 for, while 등의 반복문을 사용해야 합니다.

shorthand properties

JavaScript의 객체 리터럴에서 "shorthand properties"는 객체 속성을 간결하게 정의하는 방법을 의미합니다.
이 방법을 사용하면 변수 이름과 객체의 속성 이름이 동일한 경우, 코드를 더 간결하게 작성할 수 있습니다.

일반적으로 객체를 만들 때, 변수를 사용하여 속성을 정의하는 경우 다음과 같이 작성할 수 있습니다:

Copy code
let x = 10;
let y = 20;

let point = {
  x: x,
  y: y
};

console.log(point); // { x: 10, y: 20 }

하지만 shorthand properties를 사용하면 다음과 같이 더 간결하게 작성할 수 있습니다

Copy code
let x = 10;
let y = 20;

let point = {
  x,
  y
};

console.log(point); // { x: 10, y: 20 }

JavaScript는 자동으로 변수의 값을 가져와서 객체의 속성에 할당합니다.

이 방법은 코드를 간결하게 만들고, 가독성을 향상시키는 데 도움이 됩니다.
특히 객체의 속성이 많을 때, shorthand properties를 사용하면 코드가 더 깔끔하게 보일 수 있습니다.

Computed Property Names

객체의 속성 이름을 동적으로 계산하여 지정할 수 있는 기능을 의미합니다.
이는 객체를 만들거나 객체의 속성을 업데이트할 때, 변수 또는 표현식을 사용하여 속성 이름을 동적으로 결정할 수 있게 해줍니다.

예를 들어, 객체를 생성할 때 정적인 속성 이름 대신 동적으로 속성 이름을 결정하고 싶은 경우, Computed Property Names를 사용할 수 있습니다.
다음은 간단한 예제입니다

Copy code
let dynamicKey = "color";

let car = {
  brand: "Toyota",
  [dynamicKey]: "blue", // Computed Property Name 사용
  "year": 2022
};

console.log(car); // { brand: 'Toyota', color: 'blue', year: 2022 }

위의 예제에서 dynamicKey 변수에 할당된 값을 기반으로 속성 이름을 동적으로 결정하고 있습니다.
이 경우, car 객체에는 color라는 속성이 추가되며, 해당 속성의 값은 "blue"가 됩니다.

object lookup table

if, else if 문이 길어지게 된다면 switch case 문으로 바꾸라고 말했다.
하지만 이 방법 말고도 정말 가독성이 좋은 코드가 있다.

const getUserType = (type) => {
	switch(type) {
      case 'ADMIN':
        return '관리자'
      case 'STUDENT':
        return '학생'
      default:
        return '해당없음'
    }
}

const getUserType = (type) => {
	const USER_TYPE = {
    	ADMIN: '관리자',
        STUDENT: '학생'
    }
    return USER_TYPE[type] || '해당없음';
 // return USER_TYPE[type] ?? '해당없음';
}

console.log(getUserType('ADMIN')) // '관리자'

object Destructuring

왼쪽 코드를 보면 순서가 맞아야 들어가는 불편함이 있다.
하지만 오른쪽처럼 객체 형식으로 넣어준다면 순서를 생각해야 하는 불편함도 줄일 수 있고 어떤 값을 넣는 건지 가독성도 좋아진다.

object freeze

const data = object.freeze({
	name: 'chan',
  	age: 287
})

data.name = 'kim';
data.hobby = 'swim'
console.log(data.name) // 'chan'
console.log(data.hobby) // error

하지만 object freeze 는 깊은 복사가 불가능합니다.
그럴때는 대중적인 라이브러리인 lodash 를 쓰거나 직접 유틸 함수를 만들면 됩니다.

옵셔널 체이닝

옵셔널 체이닝(?.)은 프로퍼티나 메서드를 안전하게 참조할 수 있게 해주는 JavaScript의 기능 중 하나입니다.
특히, 중첩된 객체나 배열의 속성을 접근할 때 해당 속성이 존재하지 않는 경우 발생할 수 있는 오류를 방지하는 데 사용됩니다.

// 사용자 객체
let user = {
  id: 1,
  name: "John",
  address: {
    city: "New York",
    zipCode: "10001"
  }
};

// 주소의 우편번호를 가져오는 함수
function getZipCode(user) {
  if (user && user.address && user.address.zipCode) {
    return user.address.zipCode;
  } else {
    return "Zip code not available";
  }
}

// 주소의 우편번호를 가져오는 함수 (옵셔널 체이닝 사용)
function getZipCode(user) {
  return user?.address?.zipCode ?? "Zip code not available";
}

// 사용
console.log(getZipCode(user)); // 10001
console.log(getZipCode({}));   // Zip code not available

함수 다루기

함수

  1. 변수나 데이터에 담길 수 있다.
  2. 매개변수로 들어갈 수 있다(콜백함수)
  3. 함수가 함수를 반환 할 수 있다.(고차함수)
  4. return 값이 없으면 undefined 를 반환한다.

argument & parameter

🥞 argument

Actual parameter
실제로 사용되는, 인자

🥞 parameter

Formal parameter
형식을 갖춘, 매개변수

const getName(name) {  // parameter
	console.log(name)
}

getName('chan')		// argument

default value

기본값을 설정하게 된다면 에러를 초기에 잡아낼 수 있다.

Rest parameter

나머지 매개변수의 주의점은 파라미터가 여러개일 때 맨 마지막으로 들어가야 합니다.
function(arr1, arr2, ...arr){...}

화살표 함수

화살표 함수는 JavaScript에서 간결한 문법과 렉시컬 스코프 바인딩을 제공하는 함수 표현식입니다.
그러나 특정 상황에서는 화살표 함수가 일반 함수 표현식보다 적합하지 않을 수 있습니다. 여러 상황에서 발생할 수 있는 문제점을 살펴보겠습니다:

🥞 this 바인딩
화살표 함수는 자신만의 this를 생성하지 않고, 외부에서 가져온 this를 사용합니다. 이를 렉시컬 스코프 바인딩이라고 합니다.
때로는 이러한 특성이 원하지 않는 결과를 가져올 수 있습니다. 특히 메서드로 사용되는 경우에 주의가 필요합니다.

Copy code
function Counter() {
  this.count = 0;
  setInterval(() => {
    // 여기서의 this는 Counter 객체를 참조하지 않음
    this.count++;
    console.log(this.count);
  }, 1000);
}

const counter = new Counter();

위의 코드에서 화살표 함수 내부에서의 this는 Counter 객체가 아닌 외부 스코프에서 가져온 것이므로, this.count는 정상적으로 동작하지 않습니다.

🥞 생성자로 사용 불가
화살표 함수는 new 키워드로 호출하여 객체를 생성할 수 없습니다.
생성자로 사용하면 오류가 발생합니다. 화살표 함수는 항상 익명 함수이며 prototype 프로퍼티가 없습니다.

Copy code
const Person = (name) => {
  this.name = name; // 오류 발생
};

const john = new Person("John"); // TypeError: Person is not a constructor

🥞 arguments 객체 부재
화살표 함수에는 arguments 객체가 존재하지 않습니다.
대신, 나머지 매개변수나 Rest 파라미터를 사용해야 합니다.

Copy code
const sum = (...args) => {
  console.log(args); // arguments 대신 rest parameter 사용
};

sum(1, 2, 3); // [1, 2, 3]

따라서 화살표 함수는 특정 상황에서는 편리하게 사용할 수 있지만, 모든 상황에서 사용하기에는 고려해야 할 점이 있습니다.
함수의 사용 목적, 스코프, this 바인딩 등을 고려하여 함수를 선택하는 것이 중요합니다.

렉시컬 스코프 바인딩

렉시컬 스코프 바인딩(Lexical Scope Binding)은 JavaScript에서 변수가 어디에서 참조될지를 정하는 스코프 결정 방법 중 하나입니다.
이는 함수를 어디에서 정의했는지에 따라 결정되며, 함수가 어디에서 호출되었는지는 영향을 미치지 않습니다.

렉시컬 스코프 바인딩에서 각 함수는 자신이 정의된 위치에서의 스코프를 기억하고, 해당 스코프에 있는 변수를 참조할 수 있습니다.
이것은 함수가 호출되는 지점이 아니라 함수가 어디에서 정의되었는지에 따라 스코프가 결정된다는 의미입니다.

간단한 예제를 통해 설명하겠습니다

Copy code
function outer() {
  const outerVar = "I am from outer";

  function inner() {
    const innerVar = "I am from inner";
    console.log(outerVar); // outerVar는 outer 함수의 스코프에 있는 변수
    console.log(innerVar); // innerVar는 inner 함수의 스코프에 있는 변수
  }

  inner();
}

outer();

위의 코드에서 inner 함수는 outer 함수 내부에서 정의되었습니다. 따라서 inner 함수는 자신의 스코프뿐만 아니라 외부 함수인 outer 함수의 스코프에 있는 변수인 outerVar에도 접근할 수 있습니다. 이러한 스코프 결정 방식을 렉시컬 스코프 바인딩이라고 합니다.

순수함수

순수 함수(Pure Function)는 다음 두 가지 주요 특성을 가지고 있는 함수입니다

  1. 동일한 입력에 대해서 항상 동일한 출력을 반환합니다
    함수가 동일한 입력값을 받으면 항상 동일한 결과를 반환해야 합니다. 즉, 함수 내부에서 외부 상태에 의존하지 않아야 합니다.

  2. 부수 효과가 없습니다
    함수가 외부의 상태를 변경하거나 다른 부수 효과(side effect)를 일으키지 않아야 합니다. 부수 효과는 파일 쓰기, 네트워크 호출, 전역 변수 수정 등이 해당됩니다.

순수 함수의 예시를 살펴보면

Copy code
// 순수 함수
function add(a, b) {
  return a + b;
}

// 부수 효과가 있는 함수 (순수 함수가 아님)
let result = 0;

function impureAdd(a, b) {
  result = a + b;
  return result;
}

add 함수는 동일한 인자에 대해 항상 같은 결과를 반환하고, 부수 효과가 없습니다. 하지만 impureAdd 함수는 외부 상태를 변경하는 부수 효과가 있어 순수 함수가 아닙니다.

순수 함수는 함수형 프로그래밍에서 중요한 개념 중 하나입니다. 이러한 함수는 코드의 예측 가능성과 테스트 용이성을 향상시키며, 프로그램을 더 이해하기 쉽고 유지보수하기 쉽게 만듭니다. 또한 순수 함수를 활용하면 병렬 처리와 메모이제이션 등의 성능 최적화도 쉽게 이루어질 수 있습니다.


추상화 하기

중요한 변수이거나 할때 대문자로 쓰는게 암묵적인 룰이다.

Magic Number

//Numeric operater
const PRICE = {
	MIN: 1_000_000,
  	MAX: 1_000_000_000
}

// 더욱 엄격하게 관리
const LENGTH = Object.freeze({
	MIN: 1,
  	MAX: 5
})

네이밍 컨벤션

  1. 함수는 동사로 시작하자.
  2. _, # 을 붙이는것은 private 라는 뜻이다.

에러 다루기

유효성 검사

유효성 검사를 프론트에서 해주면 서버의 비용이 증가하지 않는 장점이 있다.

regex password validation 이라고 입력을 하면 stackoverflow 에서 유효성 검사를 간단하게
검증을 끝낼 수 있는 코드들을 많이 제공하니까 이용해보자.

최대한 개발을 할때 유효성 검사를 생각하고 또 생각해서 만드는 것을 추천하자.

추천 라이브러리
React Hook Form

try ~~ catch

개발자는 항상 예외 상황을 생각하고 개발을 해야 합니다.
밑에 예시는 보통의 상황입니다.

function handleSubmit(input){
  try {
	// 예외가 발생할 수 있는 코드들
  } catch(e) {
	// 1. 개발자를 위한 예외처리
    console.log(e)
    console.error(e)
    
    // 2. 사용자를 위한 예외처리
    alert('문제가 있습니다')
    
    // 3. 사용자의 이용 제한
    navigate('/')
    history.go('/login')
    
  } finally {
	// 무조건 실행시킬 코드들
  }
}

사용자에게 알려주기

예를 들어 input 으로 아이디와 비밀번호를 입력하고 있다고 가정해보자.
그럴때 만약 비밀번호를 입력하지 않고 로그인을 한다면 사용자에게 비밀번호를 입력하지 않았다고
알려주면서 바로 비밀번호 항목으로 이동하게 해주는 코드를 짜는게 좋다.

이런식으로 사용자에게 어떤 부분이 필요한지를 생각하면서 개발하는 습관이 중요하다.

data Attribute

css 에서도 불러서 사용할 수 있다.

profile
오류는 도전, 코드는 예술

0개의 댓글

관련 채용 정보