자바스크립트

Section 5. 자바스크립트 접근자 프로퍼티와 은닉

포칼이 2023. 3. 30. 10:58

I. 접근자 프로퍼티

const person1 = {
  age: 17,

  get koreanAge () {
    return this.age + 1;
  },

  set koreanAge (krAge) {
    this.age = krAge - 1;
  }
}

console.log(person1, person1.koreanAge); //{age: 17} 18

person1.koreanAge = 20;

console.log(person1, person1.koreanAge); //{age: 19} 20

마치 메서드나 함수처럼 생긴 get과 set이 있다. get (읽다)과 set(설정)은 각각 getter, setter 함수라 한다. 

이것들은 실제로 함수처럼 작동하지만 프로퍼티처럼 사용한다. 

그리고 스스로는 값을 갖지 않는다. 즉, 다른 프로퍼티의 값을 읽거나 저장할 때 사용한다. 

 

클래스에서도 사용 가능 하다

class KangChicken {
  constructor (name, no) {
    this.name = name;
    this.no = no;
  }
  get chainTitle() {
    return `${this.no}호 ${this.name}점`;
  }
  set chainNo(chainNo) {
    if (typeof chainNo !== 'number') return;
    if (chainNo <= 0) return;
    this.no = chainNo;
  }
}

클래스에서 get과 set을 써서 설정을 했고

const chain1 = new KangChicken('판교', 3);
console.log(chain1.chainTitle); //3호 판교점

chain1.chainNo = '4';
console.log(chain1); //KangChicken {name: '판교', no: 3}

chain1.chainNo = -1;
console.log(chain1); //KangChicken {name: '판교', no: 3}

chain1.chainNo = 4; 
console.log(chain1); //KangChicken {name: '판교', no: 4}

getter와 setter를 통해 값을 읽고 설정하는 것을 볼 수 있다. 다만 setter를 통해 '4' 와 -1을 설정을 하려고 했지만 설정이 되지 않았는데 그건 setter 함수에서 if문으로 제약을 줬기 때문이다. 이처럼 setter 메서드는 특정 프로퍼티에 값이 저장되는 방식을 조작하거나 제한하는데 사용한다.

그리고 클래스에서는 프로토타입 아래에 setter와 getter 그리고 constructor가 있는 것을 확인 할 수 있다.  

정리를 하자면 다음과 같다. 

getter

  • 반드시 값을 반환해야 함
  • 특정 프로퍼티를 원하는 방식으로 가공하여 내보낼 때 사용

setter

  • setter는 하나의 인자를 받음
  • 특정 프로퍼티에 값이 저장되는 방식을 조작하거나 제한하는데 사용

*필드 이름과 setter의 이름이 같을 때

이런 무한반복에 빠지는 오류가 날 수 있다. 

해결책은 다음과 같다.

class KangChicken {
  constructor (name, no) {
    this.name = name;
    this.no = no;
  }
  get no () { 
    return this._no + '호점'; 
  }
  set no (no) { 
    this._no = no;
  }
}

const chain1 = new YalcoChicken('판교', 3);

console.log(chain1); //KangChicken {name: '판교', _no: 3}
console.log(chain1.no); //3호점

이처럼 setter와는 다른 필드명을 사용하여 자기반복호출을 방지해야 한다.

constructor의 no는 setter를 가리키고 실제 필드명은 _no가 된다.

 

II. 은닉

캡슐화란?

  • 객체지향의 주요 요소 중 하나 - 객체 내부의 값을 감추는 (은닉) 것이다
  • 인스턴스의 프로퍼티 값을 함부로 열람하거나 수정하지 못하도록 해준다
  • 자바스크립트의 필드는 기본적으로 public 이기 때문에 은닉되지 않는다

private 필드를 통한 은닉

class Employee {
  #name = '';
  #age = 0;
  constructor (name, age) {
    this.#name = name;
    this.#age = age;
  }
}

const emp1 = new Employee('김복동', 32);

console.log(emp1); //Employee {#name: '김복동', #age: 32}

console.log(emp1.#name); // ⚠️ 오류 발생

console.log(emp1['#name']); // ⚠️ undefined 반환

필드명 앞에 #을 붙이는 것을 볼 수 있다.

주의할 점은 클래스 바로 안쪽에 정의해햐 한다는 점이다. constructor에만 하면 안된다. 

 

클래스 내에서는 private 필드에 접근이 가능하다

class Employee {
  #name = '';
  #age = 0;
  constructor (name, age) {
    this.#name = name;
    this.#age = age;
  }
  get name () {
    // [n]: n + 1 번째 글자를 반환
    return this.#name[0] + '모씨';
  }
  get age () {
    return this.#age - (this.#age % 10) + '대';
  }
  set age (age) {
    if (typeof age === 'number' && age > 0) {
      this.#age = age;
    };
  }
  getOlder(years) { this.#age += years; }
}

const emp1 = new Employee('김복동', 22);

Employee라는 클래스에 name과 age 프로퍼티가 있다. 클래스 내에서는 private 필드에 접근이 가능함으로 

getter에서는 이름 전체가 아닌 첫글자를 반환하고 age에서는 나이를 10으로 나눈 나머지 값에 '대' 를 뒤에 붙여서 반환해준다. 

setter에서는 age를 인자로 받고 받은 인자가 0보다 크고 타입이 number일때만 설정이 되게끔 제한을 뒀다. 

emp1이라는 인스턴스를 만들었다고 했을때 출력문을 보면 다음과 같다.

console.log(emp1.name, emp1.age) //김모씨 20대

emp1.age = 0;
console.log(emp1.age); //20대

emp1.age = 35;
console.log(emp1.age); //30대

emp1.getOlder(20);
console.log(emp1.age); //50대

이처럼 클래스 내에서는 private 필드에 접근이 가능한것을 확인 할 수 있다. 

 

은닉을 하면 외부에서는 접근이 불가능하지만 클래스 안에서는 constructor, 접근자 프로퍼티 또는 기타 함수에서 접근이 가능한 것을 알고 넘어가자.