지난 포스팅에서 프로토 타입에 대한 개념에 대해 정리했습니다. 오늘은 프로토 타입의 상속을 통해 부모 클래스가 자식 클래스에게 상속하는 방법에 대해 정리하고자 합니다.
Police 생성자를 정의 할때 extends 키워드를 사용합니다. extends는 프로토타입을 기반으로 동작합니다. Police.prototype.[[Prototype]]을 Person.prototype으로 설정합니다. 즉, 자식 클래스의 프로토 타입 객체의 [[Prototype]] 속성을 부요 클래스의 프로토 타입 객체로 갖습니다. 그렇게 때문에 Police 생성자에서 run 메소드를 찾지 못 할경우, 부모의 프로토 타입에서 메소드를 가져옵니다.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
run() {
console.log(`${this.name}은 달리기를 합니다.`);
}
}
class Police extends Person{
drive() {
console.log(`${this.name}이 운전을 합니다.`);
}
}
extends 키워드 뒤에는 표현식이 올 수도 있습니다. 클래스를 리턴하는 함수를 사용하면 됩니다.
extends 키워드 뒤에는 표현식이 올 수도 있습니다. 클래스를 리턴하는 함수를 사용하면 됩니다.
javascript
function f(phrase) {
return class {
sayHi() { alert(phrase) }
}
}
class User extends f("Hello") {}
new User().sayHi(); // Hello
자식 클래스는 기본적으로 부모 클래스의 메소드를 모두 상속 받습니다. 그러나 상황에 따라서 자식 클래스의 메소드 변경이 필요할 때가 있습니다. 이럴때는 자식 클래스 내부의 함수를 수정해 주면 자식 클래스는 변경된 내용의 메소드를 호출할 수 있습니다. 이렇게 자식 클래스에서 메소드를 재정의하는 것을 메소드 오버라이딩 이라고 합니다.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
run() {
console.log(`${this.name}은 달리기를 합니다.`);
}
}
class Police extends Person{
drive() {
console.log(`${this.name}이 운전을 합니다.`);
}
run() {
console.log(`${this.name}은 달리기를 시작합니다.`);
}
}
const person1 = new Person('jack');
const person2 = new Police('jack');
person1.run(); // jack은 달리기를 합니다.
person2.run(); // jack은 달리기를 시작합니다.
개발을 하다 보면 부모 메서드 전체를 교체하지 않고, 부모 메서드를 토대로 일부 기능만 변경하고 싶을 때가 생깁니다. 이럴 때 키워드 super를 사용합니다. Rabbit 클래스는 실행 중간에 부모 클래스에 정의된 메서드 super.stop()을 호출하는 stop을 가지게 됩니다.
class Person {
constructor(name, age, speed) {
this.name = name;
this.age = age;
this.speed = 0;
}
run(speed) {
this.speed = speed;
console.log(`${this.name}은 ${this.speed}km 속도로 달리기를 합니다.`);
}
}
class Police extends Person {
drive() {
console.log(`달리는 것을 멈추고 운전을 합니다.`);
}
stop() {
super.run(5); // 부모 클래스의 run을 호출해 멈추고,
this.drive(); // drive 메소드를 호출합니다.
}
}
let tom = new Police("tom", 4);
tom.run(5); // tom은 5km 속도로 달리기를 합니다.
tom.stop(); // tom은 5km 속도로 달리기를 합니다. 달리는 것을 멈추고 운전을 합니다.
화살표 함수는 super을 지원하지 않기 때문에 super에 접근하면 외부 함수를 가져옵니다. 하지만 setTimeout에 일반 함수를 사용하면 에러가 발생하게 됩니다.
class Police extends Person {
stop() {
setTimeout(() => super.stop(), 1000); // 1초 후에 부모 stop을 호출합니다.
}
}
상속 클래스 생성자를 오버리아딩을 위해서는 super(...)를 호출해야합니다. 그렇지 않으면 에러가 발생하게 되는데 그 이유는 다음과 같습니다.
이런 차이 때문에 상속 클래스의 생성자에선 super를 호출해 부모 생성자를 실행해 주어야 합니다. 그렇지 않으면 this가 될 객체가 만들어지지 않아 에러가 발생합니다.
class Person {
constructor(name, age, speed) {
this.name = name;
this.age = age;
this.speed = 0;
}
}
class Police extends Person {
constructor(name, age, height) {
super(name, age, speed); // 부모 클래스의 name, age, speed를 상속 받습니다.
this.height = height;
}
}
let tom = new Police("tom", 30, 180);
console.log(tom.name); // tom
console.log(tom.height); // 180
console.log(tom.speed); // 0
위의 코드처럼 this를 사용하기전 super를 호출하면 에러가 발생하지 않게 됩니다.
reference : https://ko.javascript.info/class-inheritance