자바스크립트

클래스,생성자

backend dev 2024. 4. 3.

 

클래스, 생성자

class Person {
    constructor(name, age) { // 생성자 메소드 이름은 자바와 다르게 constructor 이다.
        this.name = name; // 필드는 명시적으로 선언하지않고 생성자에서 초기화된다.
        this.age = age; // 이렇게해도 사용할 수 있음.
    }
    speak() { // 함수도 포함가능
        console.log(`${this.name} : hello `);
    }

    get age() { // 자바스크립트에서 게터(getter)
        //age의 getter를 정의하는 순간 this.age를 쓰는곳에서는 이 getter를 호출하게된다.
        return this.age;
    }

    set age(value) { // 자바스크립트에서 세터(setter)
        //age의 setter를 정의하는 순간 = age를 할때 setter가 사용되게 된다.
        this.age = value;
        //그렇다면 세터내부의 this.age = value 부분에서 = value 에서 setter가 재귀적으로 실행된다.
        //문제 해결은 다음 코드에서 보여준다.
    }

    /*
    즉  this.age를 하면 getter 가 호출되고 this.age = 100; 이렇게 했을시 왼쪽의 this.age에서는 게터
    오른쪽 = 100 때문에 세터가 호출된다.
    */
}

const person1 = new Person('gil', 20);

console.log(person1.name + '  ' + person1.age);
person1.speak();

constructor는 인스턴스를 생성하고 클래스 필드를 초기화하기 위한 특수한 메서드이다.

constructor는 클래스 안에 한 개만 존재할 수 있다. 2개 이상 있을 경우 Syntax Error가 발생하니까 주의하자.

 

 

자바스크립트에서 getter, setter는 함수호출 문법으로 호출 되지않는다.

 

this.age -> getter 호출

this.age = 100 ;  ->  = 100 때문에 setter도 호출 

접근자 프로퍼티

자바스크립트의 객체의 프로퍼티는 크게 두 종류로 나뉠 수 있다.

데이터 프로퍼티(data property)
접근자 프로퍼티(accessor property) 

데이터 프로퍼티는 객체 내부에 저장된 실제 데이터 값으로서 우리가 일반적인 프로퍼티라고 부르는 대상이고, 

접근자 프로퍼티는 일반적인 프로퍼티와 달리 키(key)와 값(value)을 가지지 않고 

getter와 setter라는 함수를 가지는 특수한 프로퍼티이다. 

즉, 자바스크립트 객체 속성에 접근하듯이 접근자 프로퍼티를 호출하면, 함수 호출 문법이 아니더라도 

getter & setter 함수가 호출되는 것과 같은 것이다. 

한마디로  Getter와 Setter 함수 자체가 접근자 프로퍼티이라고 보면 된다

let person = {
  /* 데이터 프로퍼티 */
  firstName: "John",
  lastName: "Doe",
  
  /* 접근자 프로퍼티 */
  get fullName() {
    return this.firstName + " " + this.lastName;
  },
  set fullName(name) {
    let names = name.split(" ");
    this.firstName = names[0];
    this.lastName = names[1];
  }
};

console.log(person.firstName); // "Jane" 출력
console.log(person.lastName); // "Doe" 출력

console.log(person.fullName); // "John Doe" 출력
person.fullName = "Jane Doe"; // Setter 호출

 

Getter & Setter 주의점

Getter 만 선언할시

 

만일 Getter만 선언하고 Setter은 선언 안했을시, 아래 예시의 fullName 접근자 프로퍼티는 getter 메서드만 가지고 있기 때문에 값을 할당하려고 하면 에러가 발생되게 된다.

let user = {
  get fullName() {
    return `...`;
  }
};

user.fullName = "Test"; // Error (프로퍼티에 getter 메서드만 있어서 에러가 발생합니다.)

 

Setter 무한 루프

만일 아래와 같이 데이터 프로퍼티명과 접근자 프로퍼티명이 둘이 같을 경우 Setter의 무한 루프에 빠져 버리게 된다.

따라서 접근자 프로퍼티의 이름을 중복이 되도록 하면 안된다.

let user = {
	name : 'inpa',
    
    get name() {
    	return user.name;	
    },
    
    set name(value) {
    	user.name = value;
    }
}

// user 객체의 name 프로퍼티 값을 변경
user.name = 'inpa2';

 

이러한 현상은 자바스크립트의 언어적 특성이라 할 수 있다. 

그리고 무한 루프가 발생하는 이유는 의외로 간단하다. 

setter 함수내에서 자기 자신을 호출하였기 때문이다.
예를들어 아래 코드에서 person.name 에 값을 할당할때 setter 함수가 호출되게 된다. 

그런데 setter 함수 내에서 this.name = value 를 통해 자기 자신에 값을 할당하고 있다. 

이 행위는 곧 자기 자신인 setter 접근자 프로퍼티 호출과 같은 행위이고 

결국은 이 재귀 행위가 무한적으로 반복되어 무한 루프가 일어나는 것이다.

따라서 이를 방지하기 위해서 접근자 프로퍼티명과 데이터 프로퍼티명을 다르게 하거나, 

내부적으로 다른 변수에 값을 저장하도록 하면 된다.

const person = {
  _name: "Inpa", // 데이터 프로퍼티명을 _name으로 변경
  set name (value) {
    this._name = value; // _name에 값을 할당
  }
};

person.name = "Inpa2";

객체.name 으로 setter를 호출할수있음, _name이 필드임.

 

 

위쪽의 예시의 게터세터 문제도 해결

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
        // this.age로 getter가 호출되고 =age로 인해 setter가 호출되서 _age라는 필드에 값이 들어간다.
        // 즉 this.age 는 게터의 return 덕분에 this._age로 치환되어서 _age라는 필드가 생성되는것이다.
    }
    get age() { // 자바스크립트에서 게터(getter)
        return this._age; // 
    }

    set age(value) { // 자바스크립트에서 세터(setter)
        this._age = value;
    }

}

 

 

댓글