[JavaScript]클래스 상속

LMH·2022년 11월 20일
0
post-thumbnail

지난 포스팅에서 프로토 타입에 대한 개념에 대해 정리했습니다. 오늘은 프로토 타입의 상속을 통해 부모 클래스가 자식 클래스에게 상속하는 방법에 대해 정리하고자 합니다.

extends 키워드

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을 가지게 됩니다.

  • super.method(...)는 부모 클래스에 정의된 메서드, method를 호출합니다.
  • super(...)는 부모 생성자를 호출하는데, 자식 생성자 내부에서만 사용 할 수 있습니다.
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을 지원하지 않기 때문에 super에 접근하면 외부 함수를 가져옵니다. 하지만 setTimeout에 일반 함수를 사용하면 에러가 발생하게 됩니다.

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

생성자 오버라이딩

상속 클래스 생성자를 오버리아딩을 위해서는 super(...)를 호출해야합니다. 그렇지 않으면 에러가 발생하게 되는데 그 이유는 다음과 같습니다.

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

이런 차이 때문에 상속 클래스의 생성자에선 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

profile
새로운 것을 기록하고 복습하는 공간입니다.

0개의 댓글