[JavaSript] 객체의 접근자 프로퍼티 get(){}, set(){}

iberis2·2023년 1월 14일
0

참고자료 프로퍼티 getter와 setter, MDN 설명 defineProperty, 프로퍼티 플래그와 설명자

[함께보면 좋은 글] 객체 property의 속성(flag)

객체의 프로퍼티는 데이터 프로퍼티와 접근자 프로퍼티로 나뉜다. 일반적으로 선언 또는 할당으로 지정되는 property는 데이터 프로퍼티이다.

let myObj = {str: 'a', num: 1}

접근자 프로퍼티는 획득자 함수 get(){}, 설정자 함수set(){} 인데, 객체 외부에서 property를 호출했을 때에는 함수가 아닌 일반 property처럼 보인다.

get(){}

getter(획득자) 라고도 불린다.
property를 읽으려고 할 때 함수를 호출(실행)하여 값을 리턴한다.
즉 함수에서 리턴하는 값이 property 값이 된다.

let myFriend ={
  get name(){
    return 'Jin Woo';
  }
}

console.log(myFriend.name); // Jin Woo

getter로만 설정한 property는 수정할 수 없다.

  • property 값을 변경하더라도, property를 호출하면 어차피 get( ){ }에 지정된 값이 리턴된다.

getter로 설정한 property를 수정할 경우

  • 일반 모드에서는 아무 일도 발생하지 않고,
  • 'use strict' 모드에서는 (설정자 함수 setter 가 지정되지 않았다는) TypeError가 발생한다.
let myFriend ={
  get name(){
    return 'Jin Woo';
  }
}

myFriend.name = 'Yu JinWoo';
// 'use strict' 모드에서는 TypeError: Cannot set property name of #<Object> which has only a getter
console.log(myFriend.name); // Jin Woo

set(파라미터){ }

setter(설정자)라고도 불린다.
property에 값을 할당하면 함수를 호출(실행)한다.

property에 할당하는 값이 argument(전달인자)로 전달되기 때문에,
무조건 1개의 parameter(매개변수)를 갖는다.

let myFriend = {
  set name (parameter) { // ② parameter로 'parameter로 전달되는 값' 이 전달된다.
  	myFriend.bestFriend = 'Jin Woo'; // ③ 함수가 실행된다.
  }
}

myFriend.name = 'parameter로 전달되는 값'; // ① setter 가 실행된다.

console.log(myFriend); // { name: [Setter], bestFriend: 'Jin Woo' }

get( ){ }와 함께 사용하며, 할당하는 property 의 값을 지정할 때 사용한다.
이 때, 무한 루프에 빠지지 않으려면, 함수 body안에서 할당하는 property 의 key와,
setter를 호출할 때 할당하는 property 의 key를 다른 이름으로 지정해주어야 한다.

/* 무한 루프에 빠지는 경우 */
let myFriend = {
  
  get name() {
    return myFriend.name;
  },

  set name(parameter) { // ② parameter로 'Jin Woo' 가 전달된다.
    // ③ 함수 실행
    myFriend.name = parameter; // ④ setter 호출 → ② 로 돌아가 setter 가 실행된다. 무한 루프에 빠진다.
  },
  
};

myFriend.name = "Jin Woo"; // ① setter 가 실행된다.
// RangeError: Maximum call stack size exceeded

console.log(myFriend.name);
/* property key를 다른 이름으로 지정하는 경우 */
let myFriend = {
  
  get name() { 
    return myFriend._name; // ⑥ 할당된 property {_name : 'Jin Woo'} 를 리턴한다.
  },

  set name(parameter) { // ② parameter로 'Jin Woo' 가 전달된다.
    // ③ 함수 실행
    myFriend._name = parameter; // ④ 전달된 'Jin Woo'가 property 키 _name 의 값으로 할당된다.
  },
  
};

myFriend.name = "Jin Woo"; // ① setter 가 실행된다.
console.log(myFriend.name); // ⑤ getter 가 실행된다.
// Jin Woo 

console.log(myFriend); // { name: [Getter/Setter], _name: 'Jin Woo' }

= (선언 또는 할당) 연산자로 property를 생성했을 경우 property의 속성configurable: true 이므로, delete 로 삭제할 수 있다.

let myFriend = {
  get name() {
    return myFriend._name;
  },

  set name(value) {
    myFriend._name = value;
  },
};

myFriend.name = "Jin Woo";
console.log(myFriend.name); // Jin Woo
console.log(myFriend); // { name: [Getter/Setter], _name: 'Jin Woo' }

/*property의 flag 속성 확인하는 매서드*/
console.log(Object.getOwnPropertyDescriptor(myFriend, "name"));
/* { get: [Function: get name],
  set: [Function: set name],
  enumerable: true,
  configurable: true } */

delete myFriend.name;
console.log(myFriend.name); // undefined
console.log(myFriend); // { _name: 'Jin Woo' }

getter 와 setter 활용

getter와 setter를 활용하여, property에 원하는 값이 할당되도록 property를 통제할 수 있다.
객체지향 프로그래밍의 특징 : 캡슐화(Encapsulation) 와 연관된다.

아래 코드처럼 활용하여 age가 음수가 되는 것을 막을 수 있다.

let user = {
  get age() {
    return this._age;
  },

  set age(value) {
    if (value < 0) {
      alert("나이는 음수가 될 수 없습니다.");
      return;
    }
    this._age = value;
  },
};

user.age = 1;
console.log(user.age); // 1

user.age = -1; // 나이는 음수가 될 수 없습니다. 팝업창이 생성됨

💡 기술적으론 외부 코드에서 user.age를 사용해 나이에 바로 접근할 수 있다. 하지만 밑줄 "" 로 시작하는 프로퍼티는 객체 내부에서만 활용하고, 외부에서는 건드리지 않는 것이 관습이다.

class에서 getter와 setter를 활용하여 모든 instance 객체를 수정하지 않고도, 인스턴스 객체의 프로퍼티를 수정(유지, 보수)할 수도 있다.

아래 코드는 birthday를 입력받아 class 에서 getter를 이용해 age 프로퍼티를 추가한다.

class User {
  constructor(name, birthday) {
    this.name = name;
    this.birthday = birthday;
  }

  /* age 프로퍼티를 추가해야할 경우 */
  get age() {
    let todayYear = new Date().getFullYear();
    return todayYear - this.birthday.getFullYear();
  }
}

let john = new User("John", new Date(1990, 3, 4));
let jane = new User("Jane", new Date(1995, 6, 1));

console.log(john.age); // 33
console.log(jane.age); // 28
profile
React, Next.js, TypeScript 로 개발 중인 프론트엔드 개발자

0개의 댓글