JavaScript - class 오버라이딩

BigbrotherShin·2020년 1월 29일
1

JavaScript

목록 보기
6/17
post-thumbnail

1. JS class 오버라이딩의 종류

  • 메서드 오버라이딩
  • 생성자 오버라이딩

부모 클래스의 메서드를 토대로 일부 기능만 변경하고 싶을 때가 있습니다. 부모 클래스 메서드의 기능을 확장하고 싶을 때도 있죠. 이럴 때, 커스텀 메서드를 만들어 작업해야 하는데, 커스텀 메서드를 호출하기 전, 후나 커스텀 메서드 중간에서 부모 메서드를 호출해야 합니다.

클래스의 "super" 키워드는 이럴 때 사용합니다.

  • super.method(...) – 부모클래스에 정의된 메서드, method를 호출함
  • super(...) – 부모 생성자를 호출함(자식 생성자 내부에서만 사용 가능)

특이 사항: 화살표 함수

화살표 함수에 대한 재고에서 살펴본 바와 같이, 화살표 함수는 super를 갖지 않습니다.

super에 접근하면, 아래 예시와 같이 super를 외부 함수에서 가져옵니다.

class Rabbit extends Animal {
  stop() {
    setTimeout(() => super.stop(), 1000); // 1초 후에 부모 stop을 호출합니다.
  }
}

화살표 함수의 super는 stop()의 super와 같기 때문에 위 예시는 의도한 대로 동작합니다. setTimeout안에서 ‘일반’ 함수를 사용했다면 에러가 발생했을 겁니다.

// Unexpected super
setTimeout(function() { super.stop() }, 1000);

2. 메서드 오버라이딩

특별한 사항이 없으면 class Animal에 있는 메서드는 ‘그대로’ class Rabbit에 상속됩니다.

그런데 Rabbit에서 stop() 등의 자체 메서드를 정의하면, 상속받은 메서드가 아닌 자체 메서드가 사용됩니다.

class Rabbit extends Animal {
  stop() {
    // rabbit.stop()을 호출할 때
    // Animal의 stop()이 아닌, 이 메서드가 사용됨
  }
}

이 때, super.method(...) 키워드를 사용합니다.

토끼가 멈추면 자동으로 숨도록 하는 코드

class Animal {

  constructor(name) {
    this.speed = 0;
    this.name = name;
  }

  run(speed) {
    this.speed += speed;
    alert(`${this.name} 은/는 속도 ${this.speed}로 달립니다.`);
  }

  stop() {
    this.speed = 0;
    alert(`${this.name} 이/가 멈췄습니다.`);
  }

}

class Rabbit extends Animal {
  hide() {
    alert(`${this.name} 이/가 숨었습니다!`);
  }

  stop() {
    super.stop(); // 부모 클래스의 stop을 호출해 멈추고,
    this.hide(); // 숨습니다.
  }
}

let rabbit = new Rabbit("흰 토끼");

rabbit.run(5); // 흰 토끼 은/는 속도 5로 달립니다.
rabbit.stop(); // 흰 토끼 이/가 멈췄습니다. 흰 토끼 이/가 숨었습니다!

3. 생성자 오버라이딩

생성자는 기본적으로 부모 constructor를 호출합니다. 부모 constructor에 인수도 모두 전달되죠. 상속 클래스에 자체 생성자가 없으면 이 일은 자동으로 발생합니다.

그러나 상속 클래스에 커스텀 생성자를 추가하려고 한다면 오류가 발생합니다.

class Animal {
  constructor(name) {
    this.speed = 0;
    this.name = name;
  }
  // ...
}

class Rabbit extends Animal {

  constructor(name, earLength) {
    this.speed = 0;
    this.name = name;
    this.earLength = earLength;
  }

  // ...
}

// 동작하지 않습니다!
let rabbit = new Rabbit("흰 토끼", 10); // Error: this is not defined.

상속 클래스의 생성자는 반드시 super(...)를 호출해야 하는데, 위 예시에선 super(...)를 호출하지 않아 에러가 발생했습니다.
일반 생성자의 실행과 상속 클래스의 생성자 실행은 객체의 this 할당에 있어 다음과 같이 다른 동작을 합니다.

  • 일반 생성자가 실행되면, 빈 객체가 만들어지고 this에 이 객체를 할당합니다.
  • 반면, 상속 클래스의 생성자가 실행되면, 위와 같은 일이 일어나지 않습니다. 속 클래스의 생성자는 빈 객체를 만들고 this에 이 객체를 할당하는 일은 부모 클래스의 생성자가 처리해주길 기대합니다.

이런 차이 때문에 상속 클래스에서 커스텀 생성자를 만들 땐 super를 반드시 호출해야 합니다. 그렇지 않으면 this가 될 객체가 만들어지지 않습니다. 당연히 에러가 발생하겠죠.

Rabbit의 생성자가 제대로 동작하게 하려면, 아래 예시와 같이 super()를 호출해야 합니다. super()는 this를 사용하기 전에 호출해주세요.

class Animal {

  constructor(name) {
    this.speed = 0;
    this.name = name;
  }

  // ...
}

class Rabbit extends Animal {

  constructor(name, earLength) {
    super(name);
    this.earLength = earLength;
  }

  // ...
}

// 이제 에러 없이 동작합니다.
let rabbit = new Rabbit("흰 토끼", 10);
alert(rabbit.name); // 흰 토끼
alert(rabbit.earLength); // 10

출처 : https://ko.javascript.info/class-inheritance

profile
JavaScript, Node.js 그리고 React를 배우는

1개의 댓글

comment-user-thumbnail
2021년 9월 25일

감사합니다 도움이 되었어요!!
화살표 함수가 super를 못 받는 이유는 자체 this가 없기 때문인건가요??

답글 달기