[클린코드 JS] 05. 객체 다루기

Serin-B·2023년 6월 26일
0

클린코드JS

목록 보기
5/15
post-thumbnail

배열에 이어 오늘은 객체를 안전하고 깔끔하게 다루는 방법에 대해 알아보자.

단축 문법 사용하기

간략하게 표현할 수 있도록 나온 최신 문법들을 익혀두면 좀 더 편리하게 객체를 생성 및 조작할 수 있다.

Shorthand Property & Method Name
객체에서 key와 value명이 같은 경우 축약해서 사용할 수 있게 만들어주는 문법이다.

const name = "영희";
const age = 20;
const gender = "female";
const info = { 
  name:name, 
  age:age, 
  gender:gender
};

//shorthand Property names 적용 코드
const info = { 
    name, age, gender 
};
console.log(info) //{name: '영희', age: 20, gender: 'female'}
const obj = {
  func: function(param) {},
};

//shorthand method names 적용 코드
const obj = {
  func(param) {},
};

Computed Property Name
객체의 key값을 표현식(변수, 함수 등)을 통해 지정하는 문법이다.

let key = "name";
let obj = {
  [key] : "영희"
}
// obj = { name: "영희" }
function sum(a, b) {
  return a + b;
}
function sayHello() {
  return 'hello';
}

let obj = {
  [`key${sum(3,5)}`] : `result is ${sum(3,5)}`,
  [sayHello()] : 'hi'
}

// obj = {
//   key8 : 'result is 8',
//   hello: 'hi'
// }

구조 분해 할당으로 요소 관리하기

객체도 구조 분해 할당으로 받아서 편하게 사용할 수 있다. 특히 리엑트에서 props 을 구조 분해 할당으로 받는 것을 흔히 볼 수 있다.

function SayHello({name}){
  return <h1>Hello, {name}</h1>
}

객체의 구조분해 할당은 함수에 매개변수를 전달할 때에도 유용하게 쓸 수 있다. 일반적으로 매개변수를 전달하면 순서가 강제된다.

function Introduce(name, age, location){
  return `My name is ${name}, I am ${age} years old and I live in ${location}.`
}

Introduce('영희', '20', 'korea')
//My name is 영희, I am 20 years old and I live in korea.
Introduce('영희', 'korea', '20')
//My name is 영희, I am korea years old and I live in 20.

그러나 객체를 활용하면 순서에 관계없이 매개변수를 전달할 수 있다.

function Introduce({name, age, location}){
  return `My name is ${name}, I am ${age} years old and I live in ${location}.`
}
const person = {
  name:'영희',
  location:'korea',
  age:'20'
}
Introduce(person)
//My name is 영희, I am 20 years old and I live in korea.

뿐만아니라 배열은 객체이므로 다음과 같이 인덱스 번호를 활용하여 객체로 구조 분해 할당 하여 데이터를 가공 및 사용할 수 있다.

const order = ['one','two','three']

//배열로 구조 분해 할당할 경우 'two' 자리를 비워두어야 함
const [one, ,three] = order

//객체로 구조 분해 할당할 경우 필요한 정보만 가져올 수 있음
const {0: first, 2: third} = order
console.log(first) // 'one'
console.log(third) // 'three'

객체로 Matcher 만들기

기존에는 주로 switch문을 사용하여 Matcher 를 만들었으나

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

이처럼 객체로 Matcher를 만들면 불필요한 분기문을 줄일 수 있다.

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

// 지역변수 만들지 않고 바로 리턴 가능
function getUserType3(type) {
    return (
      {
        ADMIN: "관리자",
    	INSTRUCTOR: "강사",
    	STUDENT: "수강생",
      }[type] ?? "해당없음"
    );
}

지역변수를 만들지 않고 바로 리턴도 가능하지만, 관심사 분리를 위해 Matcher를 다른 파일에 따로 저장하고, import로 해당 Matcher를 불러와서 사용하는 것이 가장 좋은 방법인 것 같다.

직접 접근 지양하기

객체로 특정 상태를 관리할 때, 그 객체를 직접 변경하는 것이 아니라, 그 객체를 관리하는 별도의 함수를 만들어서 관리하는 것이 좋다.

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

//직접 접근할 경우
function login(){
  model.isLogin = true;
  model.isValidToken = true;
}
function logout(){
  model.isLogin = false;
  model.isValidToken = false;
}

//리펙토링 verson
// 상태를 변경하는 함수를 만들고, 그 함수를 통해 상태를 변경한다.
function setLogin(bool){
  model.isLogin = bool;
}
function setValidToken(bool){
  model.isValidToken = bool
}

function login(){
  setLogin(true);
  setValidToken(true);
}
function logout(){
  setLogin(false);
  setValidToken(false);
}

상태 변경 함수를 생성하여 사용하면, log를 찍을 때 용이하고 훨씬 안전하게 상태를 관리할 수 있다. 무엇보다도 이렇게 상태 변경 함수를 사용하면 상태가 다음과 같이 변경될 것이라는 예측이 가능하다. 예측 가능한 코드를 작성하여, 동작을 예측할 수 있는 프로그램을 만드는 것 또한 클린 코드의 중요한 핵심이라는 것을 기억하자.

Object.freeze 로 객체 동결하기

Object.freeze는 마치 얼음땡에서 얼음!🧊 이 된 것 처럼 객체를 움직이지(변경하지) 못하게 하는 메서드이다. 이 메서드를 활용하면 객체를 누군가가 마음대로 변경하지 못하도록 막을 수 있다.

const obj = {prop : 42};

Object.freeze(obj);

obj.prop = 33;
console.log(obj.prop);// 42

obj.new = 22
console.log(obj) //{prop : 42}

단, Object.freezeshallow freeze(얕은 동결) 이므로 깊은 동결을 원할 경우에는 라이브러리를 사용하거나, deepFreeze와 같은 이름을 가지는 유틸함수를 별도로 직접 만들어서 사용하여야 한다.

shallow freeze(얕은 동결)
Object.freeze(object) 호출의 결과는 object 스스로의 직속 속성에만 적용되며, object에 대해서만 속성 추가, 제거, 재할당 연산을 방지한다. 그러나 만약 그 속성의 값이 객체라면, 그 객체는 동결되지 않으며 속성 추가, 제거, 재할당의 대상이 될 수 있다.

const person = {
  name: "영희",
  age: "20",
  location: {
    country: "korea",
    city: "seoul"
  }
};

Object.freeze(person);

employee.name = "철수"; 
employee.address.city = "busan"; 

console.log(person.name) //"영희" 
console.log(person.location.city) //"busan"

다음은 Object.freeze MDN에 나와있는 deepFreeze 함수이다. 재귀를 활용하여 깊은 동결을 구현할 수 있다.

function deepFreeze(object) {
  // 객체에 정의된 속성명을 추출
  let propNames = Object.getOwnPropertyNames(object);

  // 스스로를 동결하기 전에 속성을 동결
  for (let name of propNames) {
    let value = object[name];

    object[name] = value && typeof value === "object" ?
      deepFreeze(value) : value;
  }

  return Object.freeze(object);
}

⊕ 타입스크립트에서는 readonly 를 활용하여 동결시킬 수 있다.


참조

  • 도서 Clean Code(클린 코드) / 로버트 C. 마틴 / 2013.12.24.
  • Udemy 강의 클린코드 자바스크립트 / Poco Jang / 2023. 5.
profile
프론트엔드 개발자

0개의 댓글

관련 채용 정보