[javascript] 프로퍼티 getter와 setter

skdus·2022년 5월 8일
0

JavaScript

목록 보기
8/17
post-thumbnail

💡 객체 프로퍼티의 종류

객체 프로퍼티는 데이터 프로퍼티, 접근자 프로퍼티로 나뉜다.

  • 데이터 프로퍼티(Data Property)
    key:value 형태의 값에 문자열, 숫자, 함수, 객체, 배열 등등의 값이 들어간 모든 프로퍼티를 의미한다.
  • 접근자 프로퍼티(Accessor Property)
    접근자 프로퍼티는 함수이며, 이 함수는 값을 획득(get)하고 설정(set)하는 역할을 담당한다. 그러나 외부 코드에서는 함수가 아닌 일반적인 프로퍼티처럼 보인다.

💡 Getter & Setter

접근자 프로퍼티는 'getter(획득자)'와 ‘setter(설정자)’ 메서드로 표현될 수 있다. 그리고 객체 리터럴 안에서 getter, setter는 각각 get, set으로 나타낼 수 있다.

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

const obj = {
  macro:'hi',
  
  get hello(){
    return this.macro;
  },
  set hello(value){
    this.macro = value;
  }
};

console.log(obj.hello); // hi
obj.hello = 'hello'; 
console.log(obj.hello); // hello

다음과 같이 프로퍼티를 호출할 때 get, 프로퍼티에 값을 할당할 때 set 메서드가 실행된다.

객체 내부에서는 get, set 키워드를 사용했지만
객체 외부에서는 일반 프로퍼티처럼 obj.hello 를 사용하면 된다.

물론 getter, setter를 모두 구현할 필요는 없이 둘 중 하나만 사용할 수도 있다.

const obj = {
  macro:'hi',
  get hello(){
    return this.macro;
  },
};

console.log(obj.hello); // hi
obj.hello = 'Test'; // Error
console.log(obj.hello); // hi

다음과 같이 코드를 작성하면, setter가 존재하지 않기 때문에 getter에서 출력된 값이 변하지 않는다.

다시 한 번 더 setter 메서드를 추가한 예시를 살펴보자.

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

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

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

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

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

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


💡 접근자 프로퍼티 설명자(Descriptor)

데이터 프로퍼티의 설명자와 접근자 프로퍼티의 설명자는 다르다.

데이터 설명자에는 value, writable, enumerable, configurable 속성이 있으며
접근자 프로퍼티에는 get, set, enumerable, configurable 속성이 있다.

각각 설명자들의 개념은 다음과 같다.

  • get : 인수가 없는 함수로, 프로퍼티를 읽을 때 동작한다.
  • set : 인수가 하나인 함수로, 프로퍼티에 값을 쓸 때 호출된다.
  • enumarable : true일 시 반복문 등을 통해 나열이 가능하며 false일 때는 나열이 불가능하다. (데이터 프로퍼티와 동일)
  • configurable : true일 시 프로퍼티 삭제 / 플래그 수정이 가능하며, false일 때는 프로퍼티 삭제 플래그 수정이 불가능하다. (데이터 프로퍼티와 동일)

데이터 프로퍼티와 동일하게 접근자 프로퍼티에도 defineProperty를 통해 getter, setter를 생성할 수 있다.

const obj = {
  macro:'hi',
};

Object.defineProperty(obj, 'hello', {
  get(){
    return this.macro;
  },
  set(value){
    this.macro = value;
  }
});

console.log(obj.hello); // hi
obj.hello = 'hello world!';
console.log(obj.hello); // hello world!

Object.getOwnPropertyDescriptor(obj, 'hello');
// obj.hello 프로퍼티 또한 설명자 객체를 얻을 수 있으며
// 설명자 객체는 다음의 형태를 가진다.
// configurable: false
// enumerable: false
// get: ƒ get()
// set: ƒ set(value)

프로퍼티는 접근자 프로퍼티(get/set 메서드를 가짐)나 데이터 프로퍼티(value를 가짐) 중 한 종류에만 속하고 둘 다에 속할 수 없다는 점을 항상 유의하자.

한 프로퍼티에 get과 value를 동시에 설정하면 에러가 발생한다.


💡 getter, setter 활용하기

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

const obj = {
  get name(){
    return this._name;
  },

  set name(value){
    if(value.length < 4){
      console.log('이름은 4글자 이상이어야 합니다.');
      return;
    }
    this._name = value;
  }
};

obj.name = 'TT'; // 이름은 4글자 이상이어야 합니다.
console.log(obj.name); // undefined

obj.name = 'Totoro';
console.log(obj.name); // Totoro

다음과 같이 작성하면, obj.name 프로퍼티를 호출하면 get의 로직에 따르게 되고, obj.name = value로 name 프로퍼티에 값을 할당하면 set의 로직에 따르게 된다.

set 메서드를 통해 name 프로퍼티에 4글자 미만의 이름을 할당할 수 없으므로 'TT'를 할당할 수 없고, 'Totoro'은 4글자 이상이므로 성공적으로 할당된다.

메서드 마지막에 위치한 name 프로퍼티는 protected 속성이며, 객체 내부와 그 자손에서만 사용하겠다는 의미다. 물론, 관습상 으로 시작하는 속성은 외부에서 호출하지 않는 것이지 '호출이 불가능한 속성은 아니다'.


💡 결론

접근자 프로퍼티는 getter와 setter를 사용해 데이터 프로퍼티의 행동과 값을 원하는 대로 조정할 수 있게 해준다는 점에서 유용하다.
개발자가 임의로 데이터 프로퍼티를 검증하는 로직을 setter에 넣어서 원하는 동작을 구현한다거나, 객체의 속성 값에 대하여 제약조건을 부여할 수도, 변경이 불가능하게 만들 수도 있다.


0개의 댓글