본문 바로가기

JS skills

5 . property : 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: "mung",
  surname: "sik",

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

console.log(user.fullName); // mung sik

 

접근자 프로퍼티를 사용하면 함수처럼 호출하지 않고, 일반 프로퍼티에서 값에 접근하는 것처럼 평범하게 user.fullName을 사용해 프로퍼티 값을 얻을 수 있다. 이 때, 위의 예시에는 getter 메서드만 있기 때문에 user.fullName = "Ramos" 라고 할당하면 에러 가 발생한다. 

 

let user = {
  name: "mung",
  surname: "sik",

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

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

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

console.log(user.name); // Sergio
console.log(user.surname); // Ramos

 

getter와 setter 메서드를 구현하면 객체엔 fullName 이라는 가상의 프로퍼티가 생긴다. 가상의 프로퍼티는 읽고 쓸 순 있지만 실제로는 존재하지 않는다.

 

 


💨 getter 와 setter 활용하기 

 

getter와 setter를 '실제' 프로퍼티 값을 감싸는 wrapper 처럼 사용하면, 프로퍼티 값을 원하는 대로 통제할 수 있다. 

 

let user = {
   
    constructor(firstName, lastName, age) {
       this.firstName = firstName;
       this.lastName= lastName;
       this.age = age;
       }
       
       get age() {
          return this._age;
       }
       
       set age() {
        if (value.length < 0) {
      console.log("음수는 불가능합니다");
      return;
    }
          this._age = value;
       }
    }
    
    const user1 = new user('mung', 'sik', 28);

 

위 예시에서 age를 위한 setter 를 만들어 age 의 값이 음수가 되는걸 방지하고 있다. 

이 때, 실제 값은 _age에 저장된다. 

 


💨호환성을 키워보자.

 

데이터 프로퍼티 name 과 age 를 사용해서 사용자를 나타내는 객체를 구현한다고 가정한다.

 

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

let Mung = new User("Mung", 28);

console.log( Mung.age ); // 28

 

그런데 요구사항이 바뀌어 age 대신 birthday를 저장해야한다. 이 때, 접근자 프로퍼티를 사용하지 않으면 위의 코드에서 힘들게 만들어놓은 age를 삭제하고 수정해야한다. 그러므로 age는 그대로두고 getter 와 setter을 이용해 birthday를 추가해보도록 하자.

 

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 Mung = new User("Mung", new Date(1994, 9, 8));

console.log(Mung.birthday ); // birthday를 사용할 수 있습니다.
console.log( Mung.age );      // age 역시 사용할 수 있습니다.

 

✅ 위에서 사용한 Object.defineProperty 메서드의 문법은 다음과 같다. 

 

Object.defineProperty(obj, propertyName, descriptor)

 

obj, propertyName : 설명자를 적용하고 싶은 객체와 객체 프로퍼티

 

descriptor : 적용하고자 하는 프로퍼티 설명자

 

difineProperty 메서드는 객체에 해당 프로퍼티가 있으면 플래그를 원하는데로 변경해준다. 프로퍼티가 없으면 인수로 넘겨받은 정보를 이용해 새로운 프로퍼티를 만든다. 이 때, 플래그 정보가 없으면 자동으로 false 가 된다. 

{
  "value": "Mung",
  "writable": false,
  "enumerable": false,
  "configurable": false
}

 

따라서 

 

let user = { };

Object.defineProperty(user, "name", {
  value: "Mung",
  // defineProperty를 사용해 새로운 프로퍼티를 만들 땐, 어떤 플래그를 true로 할지 명시해주어야 합니다.
  enumerable: true,
  configurable: true
});

alert(user.name); // Mung
user.name = "Lee"; // Error