키워드 super는 다음과 같을 때 사용한다.
- super.method(...)는 부모 클래스에 정의된 메소드를 호출한다.
- super(...)는 부모 생성자를 호출하는데, 자식 생성자 내부에서만 사용할 수 있다.
1. 메소드 오버라이딩
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(); // 흰 토끼가 멈췄습니다. 흰 토끼가 숨었습니다!
2. 생성자 오버라이딩
위의 Rabbit에는 자체 constructor가 없었다. JavaScript에서 클래스가 다른 클래스를 상속받고 constructor가 없는 경우에는 아래와 같이 '비어있는 constructor가 만들어진다. 즉, 자식 클래스에 자체 생성자가 없는 경우에 자동으로 부모 constructor를 호출하고, 부모 constructor에 인자를 모두 전달한다.
class Rabbit extends Animal {
// 자체 생성자가 없는 클래스를 상속받으면 자동으로 만들어짐
constructor(...args) {
super(...args);
}
}
Rabbit에 커스텀 생성자를 추가해 보자. 커스텀 생성자에서 부모 클래스인 Animal에도 있는 name 속성과 함께 earLength 속성을 추가해 보자.
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);
에러 메시지의 내용에 따르면 상속 클래스의 생성자에서는 반드시 super(...)를 호출해야 하는데, super(...)를 호출하지 않아 에러가 발생했다. super(...)는 this를 사용하기 전에 반드시 호출해야 한다.
왜 super(...)를 호출해야 할까?
- 일반 클래스가 new와 함께 실행되면, 빈 객체가 만들어지고 this에 이 객체를 할당한다.
- 반면, 상속 클래스의 생성자 함수가 실행되면 일반 클래스에서 일어난 일이 일어나지 않는다. 상속 클래스의 생성자 함수는 빈 객체를 만들고 this에 이 객체를 할당하는 일을 부모 클래스의 생성자가 처리해주기를 기대한다.
이러한 차이 때문에 상속 클래스의 생성자에서는 super를 호출해 부모 생성자를 실행해 주어야 한다. 그렇지 않으면 this가 될 객체가 만들어지지 않아 Reference Error가 발생한다.
따라서 this를 사용하기 전에 super()를 호출하면 Rabbit의 생성자가 제대로 동작한다.
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
참고:
화살표 함수는 this나 super를 갖지 않기 때문에 주변 컨텍스트에 잘 들어맞는다.
class Rabbit extends Animal {
stop() {
setTimeout(() => super.stop(), 1000); // 1초 후에 부모 stop을 호출한다.
}
}
화살표 함수의 super는 stop()의 super와 같아서 위 예시는 의도한 대로 동작한다. 그렇지만 setTimeout안에서 아래와 같이 ‘일반’ 함수를 사용하려고 하면 클래스를 정의하는 시점에 에러가 발생한다.
setTimeout(function() { super.stop() }, 1000);
// Uncaught SyntaxError: 'super' keyword unexpected here
📚 참고 자료
https://ko.javascript.info/class-inheritance
클래스 상속
ko.javascript.info
'배워서 남 주자' 카테고리의 다른 글
디자인 패턴 - Flyweight 패턴 (2) | 2023.10.29 |
---|---|
디자인 패턴 - Mixin 패턴 (1) | 2023.10.26 |
Object.assign() (0) | 2023.10.19 |
디자인 패턴 - Proxy 패턴 (2) | 2023.10.17 |
디자인 패턴 - Provider 패턴 (0) | 2023.10.15 |