Shorthand property

자바스크립트 객체 프로퍼티, 메서드를 축약해 사용 가능하다.
키-값의 형태가 같은 경우 firstname: firstname 으로 쓸 필요없이 firstname으로 충분하다.

//적용 전
const person = {
  firstname: 'seolgi',
  lastname: 'beak',
  getFullname: function () {
    return this.firstname + this.lastname;
  },
}
//적용 후
const firstname = 'seolgi'
const lastname = 'beak'
const person = {
  firstname,
  lastname,
  getFullname() { //concise method
    return this.firstname + this.lastname;
  };
}

Computed property name

값 뿐 아니라 객체의 또한 동적으로 받을 수 있다.
React에서 익숙하게 사용하는 useState 또한 이에 해당한다.

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

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

Key-value data

강의에서는 lookup table이라는 제목이었지만, 결국 키-값 쌍 형태로 나열된 데이터에대한 이야기이기 때문에 key-value data로 바꿔서 기록한다.
키-값 형태의 데이터를 computed property name과 함께 사용하면 효율적으로 코드를 짤 수 있다.

1. if-else if문 형태

-> 리팩토링

2. switch문

type에 따라 데이터를 리턴하고, 없는 case의 경우 '해당없음'을 리턴한다.
if-else if문 보다는 흐름이 명확하다.
그렇지만 type이 추가된다면? 끊임없이 늘어지게 될 것이다.

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

3. computed property name

refactor1

function getUserType(type) {
  const USER_TYPE = {
    ADMIN: '관리자',
    INSTRUCTOR: '강사',
    STUDENT: '수강생',
    UN: '해당 없음'  //디폴트 케이스도 함께 다루면 좋다.
  }
  return USER_TYPE[type] || USER_TYPE.UN;
}

이전 코드보다 훨씬 더 명확하고 편리해보인다. 여기서 상수에 대한 정보는 따로 관리하게 된다면 관심사가 분리되어 유지보수에 더 좋을 것 같다.

refactor2 : best case

const USER_TYPE = {
  ADMIN: '관리자',
  INSTRUCTOR: '강사',
  STUDENT: '수강생',
  UN: '해당 없음'
}

function getUserType(type) {
return USER_TYPE[type] || USER_TYPE.UN;
}

#### (+) 바로 동작하게 하는 방법도 있다.
```ts
function getUserType(type) {
  return ({
    ADMIN: '관리자',
    INSTRUCTOR: '강사',
    STUDENT: '수강생',
    UN: '해당 없음'  //디폴트 케이스도 함께 다루면 좋다.
  }[type] ?? '해당없음'
  )
}

Object Destructuring

case1

function Dog(name, age, gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
}
const seolgi = new Dog('seolgi', 4, 'girl');

위의 예시처럼 함수를 만든다면 순서가 강제된다.
거기다 만일 중간에 값을 넘기고 싶지 않다면 undefined로 넘겨야한다.

case1 - refactor1

function dog({name, age, gender}) {
  this.name = name;
  this.age = age;
  this.gender = gender ?? 'girl'; //값이 들어오지 않을 경우 디폴트값을 줌.
}
const seolgi = new Dog({name: 'seolgi', age:4});

인자의 순서가 중요하지 않게 된다.
gender의 경우에는 값을 넘기지 않아도 되도록 처리되었다.

case1 - refactor2

function dog(name, {age, gender}) {
  this.name = name;
  this.age = age;
  this.gender = gender; //값이 들어오지 않을 경우 디폴트값을 줌.
}
const seolgi = new Dog('seolgi', {age: 4, gender: 'girl'});

필수 인자를 넘기도록 동작을 유도할 수 있다.
위와 같은 경우, name은 필수로 받는 값이고 age와 gender는 option값이 된다.

case2

자바스크립트에서 배열은 결국 객체라는 사실. 배열을 객체로도 다룰 수 있다.

const orders = ['first', 'second', 'third'];
['first', , 'third'] = orders; // orders의 요소가 많아지게 된다면?
const {0: st2, 2: rd2} = orders; //배열의 요소를 인덱스로 구조분해할당
st2 //first가 할당
rd2 //third가 할당

Object.freeze

객체를 동결시키는 메서드이다.

const STATUS = Object.freeze({
    PENDING: 'PENDING',
    SUCCESS: 'SUCCESS',
    FAIL: 'FAIL',
});
Object.isFrozen(STATUS) //동결되었는지 확인하는 메서드(true)

조작을 시도해도 값이 변하지 않는다. 새로운 프로퍼티를 추가해도 마찬가지이다.
그러나 깊은 복사는 커버하지 못하기 때문에 주의가 필요하다. 중첩 객체는 Object.freeze로 동결되지 않기 때문에 유틸함수를 만든다던가 다른 방법을 사용해야한다.

객체 안전하게 동결하는 방법들

  1. lodash같은 외부 라이브러리 사용
  2. freeze 유틸함수 생성해 사용
  3. typescript의 readonly 사용

freeze 유틸함수

function deepFreeze(targetObj) {
  Object.keys(targetObj).forEach(key => { //1. 객체순회
    if (객체) deepFreeze(targetObj[key]); //2. 객체인지 확인, 3.객체면 재귀
  });
  return Object.freeze(targetObj); //4. 객체가 아니라면 Object.freeze로 충분하다.
};

Prototype 조작 지양

  1. 이미 자바스크립트는 많이 발전했다.
    예전처럼 조작해서 사용할 필요가 없음.
    직접 만들어서 모듈화를 한 후 npm에 배포해 사용하는 방법도 있다.

  2. 빌트인 객체를 건들지 말 것.(몽키패치)
    프로토타입을 건들면 어디서나 사용할 수 있게 되어 위험하다.

hasOwnProperty

해당 프로퍼티를 가지고있는지 여부를 리턴한다.

const dog = {name: 'seolgi'}
dog.hasOwnProperty('name') //true

Object로부터 가져와 사용할것.

자바스크립트 특성상 프로토타입 체이닝을 통해 다른 값에 접근할 위험성이 존재한다.

Object.prototype.hasOwnProperty.call(foo, 'bar')

편하게 사용할 수 있도록 유틸함수로 만들어도 좋다.

function hasOwnProp(targetObj, targetProp){
  return Object.prototype.hasOwnProperty.call({
    targetObj, targetProp
  })
}

직접 접근 지양

자바스크립트 언어 자체에서도 객체에 직접 접근하는 것을 지양한다. getter, setter를 통해 접근하도록 한다.
단계를 나누고 레이어를 분리하는 것으로 안전한 코드를 쓸 수 있다.

const obj = {
  isLogin: false,
  isValidToken: false
}
function login() {
  obj.isLogin = true; //obj에 직접 접근 xx
  obj.isValidToken = true;
}

refactor

객체 조작하는 동작을 함수로 분리해 사용한다.

const obj = {
  isLogin: false,
  isValidToken: false
}
function setLogin(bool) {
  obj.isLogin = bool
  //로그인 동작에서 추가 동작이 필요할 때 간편하게 수정 가능하다.
  //요청: 서버에 로그를 보내야 함
  serverApi.log(obj.isLogin)
}
function setValidToken(bool) {
  model.isValidToken = bool;
  //요청: 서버에 로그를 보내야 함
  serverAPI.log(model.isValidToken);
}
function login() {
  setLogin(true);
  setValidToken(true);
}

Optional chaining

?. 를 사용한다.
if문을 남발하지 않아도 옵셔널 체이닝을 통해 간편하게 핸들링 가능하다.

profile
주니어 플러터 개발자의 고군분투기

0개의 댓글