Property flags and descriptors

객체에는 평소에는 보이지 않는 프로퍼티가 있다
writable, enumerable, configuable, getter, setter인데 이에 대해 알아보도록 하자

1. property flags


1-1. writable

writabletrue이면 값을 수정할 수 있다

let user = {
  name: "John"
};

Object.defineProperty(user, "name", {
  writable: false
});

user.name = "Pete"; // Error: Cannot assign to read only property 'name'

따라서 위와 같이 false로 설정해주면 에러가 발생한다

📌 에러는 strict mode에서만 발생된다

1-2. enumerable

enumerabletrue이면 반복문을 사용해 나열할 수 있다

let user = {
  name: "John",
  toString() {
    return this.name;
  }
};

Object.defineProperty(user, "toString", {
  enumerable: false
});

// 이제 for...in을 사용해 toString을 열거할 수 없게 되었습니다.
for (let key in user) alert(key); // name

toString메서드는 반복문을 통해 열거 할 수 없음을 확인할 수 있다

1-3. configurable

configurabletrue이면 프로퍼티 삭제나 플래그 수정이 가능하다

let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');

alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
  "value": 3.141592653589793,
  "writable": false,
  "enumerable": false,
  "configurable": false
}
*/

Math.PI = 3; // Error
// 수정도 불가능하지만 지우는 것 역시 불가능합니다.

즉 '영원히 변경할 수 없는' 객체를 만들수도 있다

2. getter, setter


객체의 프로퍼티는 두 종류로 나뉜다

  1. 데이터 프로퍼티(data property)로 일반적으로 사용했던 프로퍼티다

  2. 접근자 프로퍼티(accessor property)로 get, set의 역할을 담당한다

let obj = {
  get propName() {
    // getter, obj.propName을 실행할 때 실행되는 코드
  },

  set propName(value) {
    // setter, obj.propName = value를 실행할 때 실행되는 코드
  }
};

getter메서드는 obj.propName을 사용해 프로퍼티를 읽으려 할 때 실행되고
setter메서드는 obj.propName = value로 프로퍼티에 값을 할당하려 할 때 실행된다

let user = {
  name: "John",
  surname: "Smith",

  get fullName() {
    return `${this.name} ${this.surname}`;
  },

  set fullName(value) {
    [this.name, this.surname] = value.split(" ");
  }
};

alert(user.fullName); // John Smith

// 주어진 값을 사용해 set fullName이 실행됩니다.
user.fullName = "Alice Cooper";

alert(user.name); // Alice
alert(user.surname); // Cooper

이렇게 getter, setter 메서드를 구현하면 객체에 fullName이라는 가상의 프로퍼티가 생긴다
'가상'의 프로퍼티이기 때문에 읽고 쓸 순 있지만 실제로 존재하지는 않는다

이러한 getter, setter함수는 수정 불가능한 property를 만들때 좋다
예를 들어 생년월일을 입력하면 자동으로 나이 프로퍼티를 갖게 하고 싶은데 나이를 임의대로 바꿀 수 없게 할때

function User(name, birthday) {
  this.name = name;
  this.birthday = birthday;

  // age는 현재 날짜와 생일을 기준으로 계산됩니다.
  Object.defineProperty(this, "age", {
    get() {
      let todayYear = new Date().getFullYear();
      return todayYear - this.birthday.getFullYear();
    }
  });
}

let john = new User("John", new Date(1992, 6, 1));

alert( john.birthday ); // birthday를 사용할 수 있습니다.
alert( john.age );      // age 역시 사용할 수 있습니다.

여기서 별도의 setter함수가 없으므로 age는 불러올 수만 있고 변경할 수는 없다

📌 접근자 프로퍼티에는 데이터 프로퍼티와 다르게 value, writable가 없는 대신 get, set이라는 함수가 있는 것이다







*References

좋은 웹페이지 즐겨찾기