LoginGustBookCategories
Javascript

Class (Inheritance and Super)

thumbnailCreatehb21·2022년 01월 20일 21:40

https://images.unsplash.com/photo-1506626637585-0802df0d0269?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80



닿을 듯 말듯, 잡힐 듯 말듯하면서 안잡히는 클래스 뿌시기 2편입니다.


클래스의 상속과 Super에 대해 정리하고, 그 후 클래스의 다형성, 추상화, 캡슐화 등에 대해 정리해보겠습니다.

Inheritance and Super


상속은 한 클래스가 다른 클래스를 확장하는 방법입니다. 생성자 함수에서는 프로토타입을 이용해서 상속을 구현했었죠. 클래스에서 상속은 extends 키워드를 사용합니다.

예를 들어 League 클래스를 생성했다고 생각해보겠습니다.
세상에는 다양한 리그가 존재하지만, 각 리그마다 공통된 것들도 분명 있고, 다른 것들도 있습니다.
그렇다면 각 리그에 대한 인스턴스를 매번 따로 만들어서 동일한 작업들을 계속 반복하는 것보다
공통점을 가지는 League라는 클래스를 한번에 빡! 정의해서 각 리그 인스턴스가 가져야 하는 공통된 것들에 대해서는 League 클래스에 미리 정의해놓고, 이를 상속하는 방식으로 즉 League에 공통적으로 쓰이는 속성값을 계속 재사용하면 훨씬 간편합니다.

이렇게 재사용이 가능하게끔 하는 방식은 추후의 유지 보수성에도 엄청난 이점을 가지게 해줍니다. 만약 문제가 있다면 이 공통적인 League 클래스에 와서 한번만 해결해주면 되기 때문이죠.

한번 예제를 봐볼까요 ?

class League { constructor(name, numberOfTeams) { this.name = name; this.number = numberOfTeams; } summary() { console.log(`this league is called ${this.name}, and ${this.number} of teams are belong to ${this.name}.`); } } class Premier extends League {} class LaLiga extends League {} const premier = new Premier("PremierLeague", 20); premier.summary(); // this league is called PremierLeague, and 20 of teams are belong to PremierLeague. const laliga = new Premier("LaLiga", 20); laliga.summary(); // this league is called LaLiga, and 20 of teams are belong to LaLiga.

이처럼 extends 키워드를 통해서 League 클래스를 상속받을 수 있습니다. 그리고 이를 통해 상속을 받은 새로운 클래스에서는 부모 클래스의 모든 필드메소드가 자동적으로 포함이 됩니다. 그래서 일일히 필드와 메소드를 작성하지 않아도 동일한 것들을 계속 재사용할 수가 있는 것이죠.

그리고 위에서 말했다시피 각 리그마다 조금씩 달라지는 것들에 대해서는 각 클래스에 따로 정의를 할 수도 있겠죠?
예를 들어 챔피온스리그는 지구상 최고의 리그라고 불리우는데요, 따라서 부모 클래스인 League에서 정의한 summary 형식 그대로를 따르지 않고 다음과 같이 새롭게 재정의해주는건 어떨까요 ?

class Champions extends League { summary() { console.log("The Best of League 👍") } } const champions = new Champions("ChampionsLeague", 32); champions.summary(); // The best of League 👍

이렇게 하위 클래스에서 새롭게 부모 클래스의 메소드를 재정의해서 다른 방식으로 사용하는 것을 오버라이딩이라고 합니다.

그런데 위처럼 하게되면 그냥 완전히 덮어씌어져버리면서 부모 클래스에서 정의한 summary의 형식은 온데간데 없어지고 말죠. 그래서 만약 부모 클래스의 메소드도 그대로 사용하면서 확장하고 싶다면 다음과 같이 super 라는 키워드를 사용하시면 됩니다.

class Champions extends League { summary() { super.summary(); console.log("The Best of League 👍") } park() { console.log(`Ji Sung Park, The best player of ${this.name}.`) } } const champions = new Champions("ChampionsLeague", 32); champions.summary(); // this league is called ChampionsLeague, and 32 of teams are belong to ChampionsLeague. // The best of League 👍 champions.park(); // Ji Sung Park, The best player of ChampionsLeague.

다음으로는 constructor overriding을 알아보겠습니다.
위의 자식 클래스들은 내부에 컨스트럭터가 따로 없었는데요, 다음처럼 한번 추가해보겠습니다.

class Premier extends League { constructor() { this.flag = '🏴󠁧󠁢󠁥󠁮󠁧󠁿' } } const premier = new Premier("PremierLeague", 20); // Error !!!

이상하게 에러가 발생합니다. 다음과 같은 메세지를 띄어주네요.

Must call super constructor in derived class before accessing 'this' or returning from derived constructor

this를 사용하기전에 super 컨스트럭터, 즉 부모 생성자를 반드시 먼저 호출해야 한다고 합니다. 이러한 메세지가 뜨는 이유는 다음과 같은데요, 생성자 함수가 가지는 알고리즘에 관한 겁니다.

기본적으로 생성자함수는 실행이 되면 우선 빈 객체를 만들고, this는 이 빈 객체를 가리키게 됩니다.
그리고 this 프로퍼티들을 객체에 추가해준뒤, this를 반환하는데요.

반면, extends를 써서 만든 자식 클래스는 빈 객체를 만들고 this에 할당하는 식의 이러한 작업을 건너뜁니다. 그래서 항상 super 키워드로 부모 클래스의 컨스트럭터를 실행해줘야 하는 건데요, 따라서 다음처럼 super 키워드를 써준다면 에러가 사라지고 정상적으로 작동을 잘하게 됩니다.

class Premier extends League { constructor() { super(); this.flag = '🏴󠁧󠁢󠁥󠁮󠁧󠁿' } } const premier = new Premier("PremierLeague", 20); console.log(premier); //  {name: undefined, number: undefined, flag: '🏴󠁧󠁢󠁥󠁮󠁧󠁿'}

음.. 이게 정상적인건가요? 라고 물어보시면 당연히 정상이 아닙니다 😅.
하지만 분명히 new 키워드를 써서 생성할 때 알맞은 인자를 넣어줬는데도 namenumberundefined 이라고 나옵니다.

이러한 점을 제대로 바로잡기 위해서는 다음과 같이 자식 클래스의 컨스트럭터에도 동일한 인수를 받는 작업을 해줘야합니다.

class Premier extends League { constructor(name, number) { super(name, number); this.flag = '🏴󠁧󠁢󠁥󠁮󠁧󠁿' } } const premier = new Premier("PremierLeague", 20); console.log(premier); // {name: 'PremierLeague', number: 20, flag: '🏴󠁧󠁢󠁥󠁮󠁧󠁿'}


여기까지 상속super 키워드에 대해 정리를 해보았는데요, 이해가 좀 잘 되시나요 ? 실은 Advanced Javascript 라는 태그를 따로 만들어서 한꺼번에 모두 다 정리할까 했었는데요, 그냥 이런 식으로 중요한 주제 하나씩 잡고 포스팅하는 방식이 더 나을 것 같아서 이렇게 계속 작성을 해나가고 있네요.

아무튼 클래스에 대해서 조금은 더 친숙해지고 있다면 이러한 방식이 성공적인 것이겠죠? 클래스나 OOP와 같은 부분들이 하이 퀄리티(?)의 개발자가 되기 위해서는 필수적으로 잘 알아야 한다고 주피터 쌤이나 다른 시니어 개발자분들이 말하셨기 때문에..! 저도 꾸준히 학습을 하고 있는데요, 저 또한 블로그에 정리를 해나가면서 머리속의 조금은 어지럽게 정리가 되있는 부분들이 조금은 더 깔끔하게 정리가 되는 것 같아서 좋습니다 하하.. 이만.. 끝!
# OOP# class# javascript
© 2021 Createhb21.