클래스 상속(Class Extends)
- 연관있는 클래스에 대해 공통적인 구성 요소를 정의하여 부모 클래스를 작성
- 클래스 간에 부모 자식관계가 형성
- 추상화를 통해 코드 중복 제거 및 재사용성 증가
- 부모 클래스의 필드나 메소드를 자식 클래스에서 상속받아 호출하거나 재정의 가능
- 상속은 단 하나의 클래스만 가능 (다중상속 X)
class Whale {
_name; // 중복 프로퍼티
_residence; // 중복 프로퍼티
constructor(name, residence) {
this._name = name;
this._residence = residence;
}
// 중복 메소드
breath() {
console.log(`${this.name}가 폐호흡합니다.`);
}
swimming() {
console.log(`${this.name}가 헤엄칩니다.`);
}
}
class FlyingSquirrel {
_name; // 중복 프로퍼티
_residence; // 중복 프로퍼티
constructor(name, residence) {
this._name = name;
this._residence = residence;
}
// 중복 메소드
breath() {
console.log(`${this._name}가 폐호흡합니다.`);
}
flying() {
console.log(`${this._name}가 날아갑니다.`);
}
}
// -------------------------- 아래처럼 추상화 --------------------------
// 중복되는 프로퍼티와 메소드를 추상화 하여 부모 class에 정의 후, 자식 class는 상속받아 사용
class Mammal {
_name; // 중복 프로퍼티
_residence; // 중복 프로퍼티
constructor(name, residence) {
this._name = name;
this._residence = residence;
}
// 중복 메소드
breath() {
console.log(`${this._name}가 폐호흡합니다.`);
}
}
class Whale extends Mammal {
constructor(name, residence) {
super(name, residence);
}
swimming() {
console.log(`${this._name}가 헤엄칩니다.`);
}
}
class FlyingSquirrel extends Mammal {
constructor(name, residence) {
super(name, residence);
}
flying() {
console.log(`${this._name}가 날아갑니다.`);
}
}
const whale = new Whale('고래', '바다');
whale.breath(); // 고래가 폐호흡합니다.
whale.swimming(); // 고래가 헤엄칩니다.
const flyingSquirrel = new FlyingSquirrel('다람쥐');
flyingSquirrel.breath(); // 다람쥐가 폐호흡합니다.
flyingSquirrel.flying(); // 다람쥐가 날아갑니다.
super 키워드
- 부모 클래스의 프로토타입(prototype)에 있는 프로퍼티나 메서드에 접근하기 위한 문법
- 프로퍼티의 경우, 주로 getter/setter를 통해 구현해야 프로토타입 체인에 존재
class Mammal {
_name;
_residence;
_color = '미지정';
constructor(name, residence) {
this._name = name;
this._residence = residence;
}
// _color을 프로토타입 체인에 존재하도록 getter을 통해 구현
get _color() {
return this._color;
}
breath() {
console.log(`${this._name}가 폐호흡합니다.`);
}
}
class Whale extends Mammal {
_color = '검정';
constructor(name, residence) {
super(name, residence); // 부모의 constructor 호출
}
// 자식클래스에서 breath() 메소드를 오버라이딩
breath() {
super.breath(); // 부모의 breath() 호출
console.log(`${this._name}가 폐호흡을 하고 숨을 잘참습니다.`);
}
printColot() {
let _color = '흰색';
// 각각 로컬 변수, 인스턴스 변수, 부모의 인스턴스 변수에 접근
// `super._color`의 경우
console.log(_color, this._color, super._color);
}
}
const whale = new Whale('고래', '바다');
whale.printColot(); // 흰색 검정 검정
whale.breath();
// 고래가 폐호흡합니다.
// 고래가 폐호흡을 하고 숨을 잘참습니다.
오버라이딩(Overriding)
- 부모에게 상속받은 메소드를 자식이 재정의 하여 사용 하는 것
- 오버라이딩은 아래의 조건을 만족해야 한다.
class Mammal {
_name;
_residence;
constructor(name, residence) {
this._name = name;
this._residence = residence;
}
breath() {
console.log(`${this._name}가 폐호흡합니다.`);
}
}
class Whale extends Mammal {
constructor(name, residence) {
super(name, residence);
}
// 자식클래스에서 breath() 메소드를 오버라이딩
breath() {
console.log(`${this._name}가 폐호흡을 하고 숨을 잘참습니다.`);
}
swimming() {
console.log(`${this._name}가 헤엄칩니다.`);
}
}
const whale = new Whale('고래', '바다');
whale.breath(); // 고래가 폐호흡을 하고 숨을 잘참습니다.
상속 관계에서의 생성자(Construct)
- 자식 클래스는 부모 클래스의 속성과 메서드를 확장하는 것이므로, 부모의 구조가 먼저 준비되어야 할 필요가 있음
- 자식 클래스의 constructor에서 반드시
super()를 먼저 호출하고, this 키워드를 사용
- 만약
super()를 호출하기 전에 this에 접근하려고 하면 ReferenceError가 발생
class Mammal {
_name;
_residence;
constructor(name, residence) {
this._name = name;
this._residence = residence;
}
breath() {
console.log(`${this._name}가 폐호흡합니다.`);
}
}
// 잘못된 예시
class Whale extends Mammal {
_color;
constructor(name, residence) {
this._color = '검정'; // 인스턴스시 여기서 ReferenceError 발생
super(name, residence);
}
swimming() {
console.log(`${this._name}가 헤엄칩니다.`);
}
}
// 잘 된 예시
class FlyingSquirrel extends Mammal {
_foods;
constructor(name, residence) {
super(name, residence);
this._foods = '도토리'; // super() 메소드 이후 this 접근
}
flying() {
console.log(`${this._name}가 날아갑니다.`);
}
}
const whale = new Whale('고래', '바다');
const flyingSquirrel = new FlyingSquirrel('다람쥐', '산');
Getter
- 객체의 프로퍼티 값을 단순한 값 읽기를 넘어 특정 로직을 실행 또는 private 프로퍼티의 값을 외부로 전달하는 특별한 메서드
- 겉보기에는 일반적인 프로퍼티처럼 보이지만, 실제로는 함수처럼 동작