[JavaScript] Class, 상속(Inheritance)과 다형성(Polymorphism)

feelslikemmmm·2020년 11월 7일
5

TIL

목록 보기
35/36
post-thumbnail

서론

javascript class는 기존의 존재하던 javascript 위에 추가된 것이기 때문에

완전히 새롭게 완벽하게 추가 된 것이 아니라

기존에 존재하던 prototype을 베이스로 한 것에 기반해서

그 위에 간편하게 쓸 수 있도록 문법만 class로 추가된 것입니다

그런것들을 syntacticla sugar라고 하는데, 즉 문법상으로 달달한

가짜의 편리함을 제공한다는 뜻입니다

Class

이전 포스팅에서 다뤘듯이 클래스 는 template에 속하고

template를 이용해서 실제로 data를 넣어서 만드는 것이 Object 입니다

JavaScript에서는 클래스가 도입된지 얼마 되지 않았습니다 ES6에서 추가되었습니다

그렇다면 클래스가 없었을때는 어떻게 만들었을까요? 객체 지향 언어가 아니었을까요?

클래스가 도입되기 전에는 클래스를 정의하지 않고, 바로 Object를 만들 수 있었습니다

Object를 만들때 function을 이용해서 template를 만드는 방법이 있었습니다

이 방법은 나중에 따로 포스팅에서 다루도록 하겠습니다

이 포스팅에서는 새로 추가 된 class를 이용해서 template를 만드는 법을 알아보겠습니다


Class declarations

class 라는 키워드를 사용해서 Person이라는 클래스를 만들었습니다

Person 클래스에는 name과 age라는 Fields가 있고 speak()라는 메소드도 정의되어 있습니다

constructor(생성자)를 이용해서 나중에 Object를 만들때 필요한 데이터를 전달 합니다

전달받은 data를 위 사진에서 Person 클래스에 존재하는 두가지 Fields인 name과 age에 할당해줍니다

speak() 메소드는 단순하게 클래스에 있는 this.name과 hello를 출력 합니다

Object를 생성해 보겠습니다

new 키워드를 이용해서 새로운 instance를 만들었습니다

이를 확인해보기 위해서 console창에 feelslike.name과 feelslike.age 또 speak메소드를 실행해보겠습니다

name과 age가 잘 출력되었고 메소드도 잘 호출되었습니다


Getter and setter

User라는 클래스를 만들고 새로운 유저인 user1을 만들었습니다

이름은 steveJobs이고 나이는 -1로 지정했습니다 console창에 user1의 age를 출력하면 -1이 출력됩니다

그런데 이것은 객체지향적 개념으로 봤을때 말이 안됩니다 사람의 나이는 -1이 없기 때문이죠

이렇게 클래스를 사용하는 사용자가 잘못 사용해도 우리가 조금 더 방어적인 자세로 만들 수 있는 것이

Getter 와 setter 입니다

user의 age가 -1 이라는 것은 말이 되지 않기 때문에 get이라는 키워드로 값을 리턴하고

set이라는 키워드를 이용해서 값을 설정할 수 있습니다 set은 값을 설정하기 때문에 value를 받아와야 합니다

그런데 이렇게만 하면 계속 call stack이 초과되었다는 에러가 발생할 수 있습니다

age라는 getter를 정의하는 순간 this.age는 메모리에 올라가있는 데이터를 읽어오는 것이 아니라

getter를 호출하게 됩니다

그리고 우리가 setter를 정의하는 순간 this.age = age; 부분 즉,

값을 할당할때 바로 메모리의 값을 할당하는 것이 아니라 setter를 호출하게 됩니다

그 말은 우리가 setter안에서 전달 된 value를 this.age에 할당할때

메모리의 값을 업데이트 하는 것이 아니라 setter를 호출하게 됩니다

이 과정이 무한정 반복되면서 call stack이 초과되었다는 에러가 발생하는 것 입니다

이것을 방지하기 위해서는 getter와 setter안에서 사용하는 변수를 다른 이름으로 설정해야 합니다

보통은 _기호를 사용해서 getter와 setter안에 변수를 선언합니다

이제는 User라는 클래스안에는 3개의 Fields가 있습니다

firstName, lastName 그리고 기호가 붙어있는 this._age까지 3개 입니다

자 이제 setter에 age로 입력받은 value가 0보다 작으면 0을 출력하고

아닌 경우에는 입력받은 age를 출력하도록 작성했습니다

user1.age를 콘솔에 출력해보면 -1을 입력했음에도 불구하고 0이 출력되게 됩니다

Fields에는 _ 기호가 들어간 this._age가 있지만 user1.age라고 호출할 수 있고 또,

this.age에 값을 할당할 수 있는 이유는 class 내부적으로 getter와 setter를 이용하기 때문입니다


Public & Private

Fields(public, private)는 너무 최근에 추가되어서 아직 사용하는 개발자가 많지 않습니다

생성자를 쓰지않고 Field를 정의할 수 있는데 그냥 정의하게 되면 public 즉 외부에서 접근이 가능하고

#기호를 사용하게 되면 private Field 인데 이렇게 정의하게 되면

클래스 내부에서만 값이 보여지고 접근이 되고 변경이 가능해집니다

클래스 외부에서는 값을 읽을수도 변경할 수도 없습니다

console.log(experiment.publicField);를 실행해보면 2가 나오고

console.log(experiment.privateField);를 실행해보면 undefined가 나옵니다

이것은 정말 최근에 추가되어진 것이기 때문에 safari에서도 지원이 되지 않는다고 합니다

사용을 위해서는 babel을 이용해야 합니다 지금 쓰기에는 너무 이르다고 합니다


Static properties and methods

Static도 비교적 최근에 만들어졌습니다

클래스안에 있는 Fields와 method들은 새로운 Object를 만들때마다 복제되어서

값만 우리가 지정한 값으로 변경되어서 만들어 집니다

간혹 이런 오브젝트, 데이터에 상관없이 클래스가 가지고 있는 고유한 값과

데이터에 상관없이 동일하게 반복적으로 사용되어지는 method가 있을 수 있습니다

그런것들을 static이라는 키워드를 사용해서 만들면 오브젝트에 상관없이 클래스 자체에 연결되어 집니다

예를들어 위 사진에서처럼 article1과 article2를 만들고 console.log(atricle1.publisher)를 실행하면

undefined가 출력이 됩니다 그 이유는 static을 사용해서 선언되어졌기 때문입니다

console.log(Article.publisher); 를 실행하면 우리가 원하던 값이 출력되는 것을 볼 수 있습니다

그래서 static함수를 호출할때도 클래스 이름을 이용해서 Article.printPublisher(); 로 호출할 수 있습니다

이것은 typeScript를 할때 많이 사용하게 됩니다

Object에 상관없이 들어오는 data에 상관없이 공통적으로 클래스에서 사용할 수 있는 것이라면

static과 staticMethod를 이용해서 사용하는 것이 메모리의 사용을 조금 더 줄여줄 수 있습니다


상속(Inheritance)과 다형성(Polymorphism)

네모, 동그라미, 세모 같은 도형을 만들 수 있다고 하면 클래스로 정의할 때 어떻게 만들 수 있을까요?

네모, 동그라미, 세모는 도형(Shape) 입니다 공통적으로 들어가는 속성은 너비와 높이 색상 등 일 것입니다

이 반복되는 속성들을 도형(Shape)에 정의하고 재사용하면 조금 더 쉬워지지 않을까요?

타이핑이 줄어들고, 재사용이 가능하기 때문에 유지 보수도 쉽습니다

만약 문제가 생긴다면 공통적인 속성이 들어있는 Shape에서 수정하면 됩니다

Shape 클래스에 width, height, color 3가지의 Fields가 있고

darw, getArea라는 2개의 method가 있습니다

그리고 extends라는 키워드를 이용해서 Shape의 Fields와 method를 복사할 수 있습니다

이 상태에서 직사각형 클래스인 Rectangle을 정의 하고싶다면

class Rectangle extends Shape {} 처럼 extends 키워드를 사용하면 됩니다

이제 Rectangle class는 Shape의 Fields와 method를 포함하고 있습니다

new 키워드를 이용해서 rectangle을 생성하고 결과를 보면

rectangle.draw()의 실행결과는 drawing blue color of

rectangle.getArea()의 실행결과는 400이 나온것을 알 수 있습니다

이번에는 Shape 클래스를 이용해서 삼각형의 특징을 가진 class를 만들어 보려고 합니다

그런데 삼각형의 면적을 구하는 방법은 width와 height를 곱한 뒤 나누기 2를 해야 하는데

getArea() method는 width와 height를 곱하는 역할만 하고 있습니다

또 draw() method는 입력받은 color와 함께 메세지를 출력해주는데 저는 도형의 모양도 출력하고 싶습니다

어떻게 할 수 있을까요?

우리가 필요한 함수만 재정의해서 사용하면 됩니다

아까처럼 extends로 Shape의 Fields와 method를 복사 하였고

Triangle 클래스에서 draw()와 getArea()를 재정의 해주었습니다

draw() method에서 console.log('🔺'); 를 추가하였는데 이렇게 하면

기존의 메세지가 출력되지 않습니다.

그래서 Shape의 method를 그대로 상속받으려면 super 키워드를 이용하면 됩니다

그러면 triangle.draw(); 의 실행 결과는 drawing re color of 와 🔺 가 됩니다

또한 getArea() method도 삼각형의 면적을 구하는 공식으로 재정의 해주었습니다

triangle.getArea(); 의 실행 결과는 200이 나온 것을 알 수 있습니다

이것이 바로 상속과 다형성 입니다

profile
꾸준함을 잃지 말자는 모토를 가지고 개발하고 있습니다 :)

1개의 댓글

comment-user-thumbnail
2022년 8월 27일

안녕하세요! 혹시 첨부하신 코드 스니펫 테마가 뭔지 알 수 있을까요?

답글 달기