클래스 상속을 사용하면 클래스를 다른 클래스로 확장할 수 있다.
extends
키워드를 사용하여 클래스 상속을 생성한다.
들어가기 전에 '다형성' 에 대해서 먼저 알아보자!
다형성(polymorphism) 이라는 단어는 원래 '여러 개의 형태를 갖는다' 라는 의미의 그리스어에서 유래했다. 또 사전에서 찾아보면 poly(하나 이상), morph(형태)가 합성된 단어로 '하나 이상의 형태'를 뜻한다.
다형성의 개념에 대해 먼저 알아본다면 객체지향에서 다형성의 개념이 적용된 두 가지 형태인 오버로딩 과 오버라이딩 을 이해하기 좋을 것이다.
다형성 ex.1 )
다형성 ex.2 )
위의 예에서 살펴보면 하나의 행위('타다', '면적을 계산하다')가 결과를 여러개 만들어 내는 것을 알 수 있다. 이는 프로그램 측면에서 같은 메세지에 대해 이 메세지를 수신하는 객체마다 다르게 행동하는 것을 의미한다. 동일한 메서드 이름을 사용하지만 메서드에 대해 클래스마다 모두 다르게 구현되는 개념이 다형성이다.
✏️ 예제를 작성하면서 과정을 다시 복습 & 정리해보기.
class Shape {
constructor(width, height, color){
this.width = width;
this.height = height;
this.color = color;
}
draw(){
return (`drawing ${this.color} color !`);
}
getArea(){
return this.width * this.height;
}
}
let shape = new Shape(3, 3, 'blcak');
console.log(shape.width); // 3
console.log(shape.draw()); // drawing blcak color !
✍️
(1) Shape
이라는 클래스를 만들었다. Shape
안에는 세 가지의 fields
(width, height, color)가 있고, 두 가지의 methods
(draw(), getArea())가 있다.
(2) new Shape(...)를 호출해서 shape
라는 객체를 만들었다. 넘겨받은 인수와 함께 constructor
가 실행되고 할당이 잘 되었는지 확인!
❓ 만약 Rectangle
이라는 클래스를 만든다고 가정해보자. 그리고 그 안의 데이터가 Shape
클래스와 동일한 데이터가 필요하다면 ▶ extends(연장하다)
를 통해 상속할 수 있다.
✏️ Shape
를 상속받는 class Rectangle
을 만들어보자.
class Shape {
constructor(width, height, color) {
this.width = width;
this.height = height;
this.color = color;
}
draw() {
return (`drawing ${this.color} color !`);
}
getArea() {
return this.width * this.height;
}
}
// ▼
class Rectangle extends Shape {}
const rectangle = new Rectangle(10, 20, "blue");
console.log(rectangle.width); // 10
console.log(rectangle.draw()); // drawing blue color !
console.log(rectangle.getArea()); // 200
✍️
(1) 클래스 확장 문법 class Child extends Parent
을 사용해서 Rectangle
클래스를 확장해보자.
(2) Shape
에서 정의한 fields
와 methods
가 자동적으로 Rectangle
에 포함된다.
(3) 콘솔을 통해 결과를 확인해보자!
✏️ Shape
를 상속받는 class Triangle
을 만들고 Shape
내에서 수정해보자.
class Shape {
constructor(width, height, color) {
this.width = width;
this.height = height;
this.color = color;
}
draw() {
return (`drawing ${this.color} color :) !! `); // ◀ 여기서 수정하면
}
getArea() {
return this.width * this.height;
}
}
// ▼ Rectangle
class Rectangle extends Shape {}
const rectangle = new Rectangle(10, 20, "blue");
console.log(rectangle.width); // 10
console.log(rectangle.draw()); // drawing blue color :) !! // ◀ 수정됨
console.log(rectangle.getArea()); // 200
// ▼ Triangle
class Triangle extends Shape {}
const triangle = new Triangle(5, 30, 'white');
console.log(triangle.height); // 30
console.log(triangle.draw()); // drawing white color :) !! // ◀ 수정됨
console.log(triangle.getArea()); // 150
✍️
(1) 이렇게 상속을 사용하게 되면 공통되어지는 데이터를 일일이 작성하지 않고도 extends
를 사용해서 계속 재사용할 수 있다.
(2) 만약 공통적으로 수정이 필요할 때에도 class Shape
안에서 수정을 하면 동시에 적용된다.
❓ 앞에서 class Rectangle
과 class Triangle
을 만들었는데 이것들은 각각 Shape
의 fileds
를 사용해서 getArea
을 구했다. 그런데 삼각형의 넓이를 구하는 공식은 밑변 * 높이의 곱의 1/2로 구해야 한다.
✏️ 여기서 필요한 함수만 재정의해서 쓸 수 있다.(오버라이딩)
우리가 앞에서 살펴본 '다형성' 이 빛을 발하는 순간이다!
class Shape {
constructor(width, height, color) {
this.width = width;
this.height = height;
this.color = color;
}
draw() {
return `drawing ${this.color} color :) !! `;
}
getArea() {
return this.width * this.height;
}
}
// ▼ Rectangle
class Rectangle extends Shape {}
const rectangle = new Rectangle(10, 20, "blue");
console.log(rectangle.width); // 10
console.log(rectangle.draw()); // drawing blue color :) !!
console.log(rectangle.getArea()); // 200
// ▼ Triangle
class Triangle extends Shape {
getArea() {
return (this.width * this.height) / 2; // 자체정의 메소드
}
draw() {
return (`${super.draw()} 🔼 `); // super 키워드 사용
}
}
const triangle = new Triangle(5, 30, "white");
console.log(triangle.height); // 30
console.log(triangle.draw()); // drawing white color :) !! 🔼
console.log(triangle.getArea()); // 75
✍️
(1) 이렇게 메소드를 오버라이딩 할 수 있다.
Triangle
에서 메소드를 자체적으로 정의하면, 상속받은 메소드가 아닌 자체 메소드가 사용된다. ( 더이상 Shape
에 정의된 함수가 호출되지 않게 된다. )super
를 사용한다.(2) 부모 메소드의 draw()
도 출력하고, Triangle
에서 오버라이딩으로 재정의한 draw()
도 함께 출력하고 싶을 때 키워드 super
를 사용한다.
super.draw()
: 부모의 draw 라는 의미이다. 이 함수를 호출하면 부모의 메소드도 호출된다.
super.method(...)
는 부모 클래스에 정의된 메소드, method
를 호출한다.super(...)
는 부모 생성자를 호출하는데, 자식 생성자 내부에서만 사용 할 수 있다.instanceof 연산자는 생성자의 prototype 속성이 객체의 프로토타입 체인 어딘가 존재하는지 판별한다.
object instanceof constructor
object
: 판별할 객체constructor
: 판별 목표 함수📌 위의 클래스상속 예제를 통해 instanceof
를 사용하면 아래와 같은 결과가 나온다.
console.log(rectangle instanceof Rectangle); // true
console.log(triangle instanceof Rectangle); // false
console.log(triangle instanceof Triangle); // true
console.log(triangle instanceof Shape); // true (Shape을 상속했으므로)
console.log(triangle instanceof Object); // true
✍️
마지막행의 triangle instanceof Object
→ true
: 자바스크립트에서 만든 모든 오브젝트 클래스들은 자바스크립트에 있는 오브젝트를 상속한 것이기 때문이다. 그 말은 우리가 어떤 오브젝트든지 이 공통적으로 존재하는 메소드를 쓸 수 있다는 것이다.( toString(), constructor() 등 )
// 위의 예제를 빌려와서 작성
class Triangle extends Shape {
getArea() {
return (this.width * this.height) / 2;
}
draw() {
return (`${super.draw()} 🔼 `);
}
toString(){
return (`Triangle 이고, 색은 ${this.color} 입니다.`)
}
}
const triangle = new Triangle(5, 30, "white");
console.log(triangle.toString()); // Triangle 이고, 색은 white 입니다.
📌 자바스크립트 내장객체 - JavaScript의 내부에 포함되어 있는 오브젝트는 어떤 것들이 있는지 카테고리로 묶여서 정리되어 있다.
reference
javascript.info MDN-instanceof dreamcoding 네이버지식백과-다형성