클래스 상속(Class Extends)

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 키워드

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)

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