클린코드 자바스크립트[7] 객체 다루기

Doozuu·2023년 12월 13일
0

Javascript

목록 보기
94/99

shorthand properties

const firstName = "poco";
const lastName = "jang";

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

아래처럼 속성을 축약해서 나타낼 수 있다.

const firstName = "poco";
const lastName = "jang";

const person = {
  firstName, // shorthand properties
  lastName, // shorthand properties
  getFullName() { // concise method
    return this.firstName + this.lastName; 
  },
};

// {
//  firstName: 'poco',
//  lastName: 'jang',
//  getFullName: [Function: getFullName]
// }



computed property name

계산된 값을 속성명으로 사용할 수 있다. (대괄호 안에 넣어서 사용)

const handleChange = (e) => {
  setState({ [e.target.name]: e.target.value });
};

return (
  <>
    <input value={state.id} onChange={handleChange} name="name" />
    <input value={state.password} onChange={handleChange} name="password" />
  </>
);



lookup table

key, value가 리스트로 쭉 나열되어 있는 것

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

// lookup table => 굿!
function getUserType(type) {
  // 상수 파일을 따로 관리하여 import해서 간단하게 사용할 수도 있음
  const USER_TYPE = {
    ADMIN: "관리자",
    INSTRUCTOR: "강사",
    STUDENT: "수강생",
    UNDEFINED: "해당 없음",
  };

  return USER_TYPE[type] ?? USER_TYPE.UNDEFINED;
}

// 바로 리턴하기
function getUserType(type) {
  return (
    {
      ADMIN: "관리자",
      INSTRUCTOR: "강사",
      STUDENT: "수강생",
    }[type] ?? "해당 없음"
  );
}



object destructuring

아래처럼 작성하면 매개변수 순서가 강제된다.

function Person(name, age, location) {
  this.name = name;
  this.age = age;
  this.location = location;
}

const poco = new Person("poco", 30, "korea");
// 값을 안 넘기려면 아래처럼 undefined로 써야 함
// const poco = new Person("poco", undefined, "korea");

object destructuring을 사용하면 순서를 지키지 않아도 되서 훨씬 편리하다.

function Person({ name, age, location }) {
  this.name = name;
  this.age = age ?? 30;
  this.location = location ?? 'korea';
}

// 순서 달라도 상관없음
const poco = new Person({
  age: 30,
  name: "poco",
  location: "korea",
});

// 값 안 넘겨도 상관없음
const poco = new Person({
  location: "korea",
});

name만 필수로 받고 나머지는 선택으로 받으려면 아래처럼 만들 수 있다.

function Person(name, { age, location }) {
  this.name = name;
  this.age = age;
  this.location = location;
}

const poco = new Person("poco", {
  age: 30,
  location: "korea",
});

배열에서 특정 변수를 꺼낼 때도 활용할 수 있다.

const orders = ["First", "Second", "Third"];

// 배열로 하면 안 쓰는 값을 비워두어야 하지만 객체로 하면 원하는 값만 골라 쓰면 된다.
// const [first, , third] = orders;
const { 0: first, 2: second } = orders;

React에서도 props를 다룰 때 많이 사용되고 있다!



Object.freeze

객체를 동결시킬 수 있다.(원본 유지, 객체를 변경할 수 없음)

  • Object.isFrozen() : 객체 동결 여부 확인
const STATUS = Object.freeze({
  PENDING: "PENDING",
  SUCCESS: "SUCCESS",
  FAIL: "FAIL",
  OPTIONS: {
    GREEN: "GREEN",
    RED: "RED",
  },
});

Object.isFrozen(STATUS); // true

주의 : 깊은 영역까지는 freeze가 되지 않는다.

const STATUS = Object.freeze({
  PENDING: "PENDING",
  SUCCESS: "SUCCESS",
  FAIL: "FAIL",
  OPTIONS: {
    GREEN: "GREEN",
    RED: "RED",
  },
});

STATUS.OPTIONS.GREEN = "G"; // 이렇게 깊은 영역은 수정할 수 있다.
Object.isFrozen(STATUS.OPTIONS.GREEn); // false

해결 방법

  1. 대중적인 유틸 라이브러리(lodash)
  2. 직접 유틸 함수 생성(deep freeze하는 함수 생성)
    • 객체 순회, 값이 객체인지 확인, 재귀적으로 object.freeze()
  3. stackoverflow
  4. TypeScript => readonly 사용



Prototype 조작 지양하기

  1. 이미 JS는 많이 발전했다.(prototype을 조작하지 않아도 됨)
    1-1. 직접 만들어서 모듈화
    1-2. 모듈화한 것을 배포(NPM)하기
  2. JS 빌트인 객체를 건들지 말자.



hasOwnProperty

특정 프로퍼티를 가지고 있는지 확인

주의 : hasOwnProperty가 이미 선언되어 있으면 해당 메서드가 덮어씌워질 수 있다.
이럴 때는 Object.prototype.hasOwnProperty.call()를 사용하면 안전하게 쓸 수 있다.

const foo = {
  hasOwnProperty: function () {
    return "hasOwnProperty";
  },
  bar: "string",
};

console.log(foo.hasOwnProperty("bar")); // x
console.log(Object.prototype.hasOwnProperty.call(foo, "bar")); // o



직접 접근 지양하기

model 객체를 여러 함수에서 직접 변경하고 있다.

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

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

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

객체를 직접 다루는 영역을 따로 분리하여 더 안전하게 쓸 수 있다.

// 직접 접근 지양
const model = {
  isLogin: false,
  isValidToken: false,
};

// model에 대신 접근
function setLogin(bool) {
  model.isLogin = bool;
}

// model에 대신 접근
function setValidToken(bool) {
  model.isValidToken = bool;
}

// model에 직접 접근 x
function login() {
  setLogin(true);
  setValidToken(true);
}

// model에 직접 접근 x
function logout() {
  setLogin(false);
  setValidToken(false);
}

예측 가능한 코드를 작성해서 동작이 예측 가능한 앱 만들기!



Optional Chaining

?. : 선택적으로 프로퍼티를 선택할 수 있다.

예시

const obj = {
  name: "value",
};

obj?.name;

서버에서 데이터를 받아올 때 값이 있는지 확인하려면

const response = {
  data: {
    userList: [
      {
        name: "Lee",
        info: {
          tel: "010",
          email: "lee@gmail.com",
        },
      },
    ],
  },
};

// 방법 1 : if문으로 하나하나 점검 => 너무 번거로움
function getUserEmailByIndex(userIndex) {
  if (response.data) {
    if (response.data.userList) {
      if (response.data.userList[userIndex]) {
        return response.data.userList[userIndex].info.email;
      }
    }
  }

  return "알 수 없는 에러가 발생했습니다.";
}

// 방법 2 : && 으로 단축 => 여전히 김
function getUserEmailByIndex(userIndex) {
  if (
    response.data &&
    response.data.userList &&
    response.data.userList[userIndex]
  ) {
    return response.data.userList[userIndex].info.email;
  }

  return "알 수 없는 에러가 발생했습니다.";
}

// 방법 3 : optional chaining 활용 => 간편함!
function getUserEmailByIndex(userIndex) {
  if (response.data?.userList?.[userIndex]?.info?.email) {
    return response.data.userList[userIndex].info.email;
  }

  return "알 수 없는 에러가 발생했습니다.";
}
profile
모든게 새롭고 재밌는 프론트엔드 새싹

0개의 댓글