상속(Inheritance)
객체들 간의 관계를 구축하는 방법
클래스 상속
클래식끼리
extends
예약어로 상속할 수 있다. 상속하는 클래스는 부모 클래스가 되고, 상속받는 클래스는 자식 클래스가 된다. 공통되는 속성이나 메서드는 부모 클래스로부터 상속받는다.
프로토타입에서는 상속 개념을 이용하기 위해서 프로토타입 체인
이라는 것을 이용한다. 이 방법은 다소 복잡한 감이 있는 와중에 ES6에서 class
를 지원하면서 extends
키워드를 통해 상속을 더 쉽게 구현할 수 있게 되었다.
객체 지향 프로그래밍에서 크게 3요소로 꼽는 캡슐화
, 상속
, 다형성
세 가지 중 상속을 말한다.
상속은 객체들 간의 관계를 구축하는 방법이다. 클래스로 객체가 정의되고 고전 상속에서, 클래스는 기반 클래스, 수퍼 클래스 또는 부모 클래스 등의 기존 클래스로부터 속성과 동작을 상속받을 수 있다. 그 결과로 생기는 클래스를 파생 클래스, 서브 클래스 또는 자식 클래스라고 부른다.
즉, 상속은 자식 클래스(서브 클래스)에서 부모클래스의 속성과 동작 등의 기능을 사용할 수 있도록 해준다. 자식 클래스에서 부모 클래스의 함수를 불러서 사용하거나 변수들을 불러 사용할 수 있다.
보통 부모와 자식 간의 유전, 상속이라고 하는 부분을 생각하면 쉽다. 자식은 부모의 키와 외모, 성품, 재산 등을 물려받듯 자식 클래스는 부모 클래스의 기능을 물려받는다. 상속을 받는 자식 클래스의 경우 부모의 소스 코드를 복사할 필요 없이 부모 클래스의 프로퍼티와 메서드를 모두 사용할 수 있을 뿐 아니라 필요한 기능을 추가해 확장할 수도 있다.
상속 시에는 기존 클래스로부터 extends 키워드를 통해 상속을 받는다.
상속을 사용하는 이유는 크게 두가지가 있는데
class shape {
constructor(width, height, color){
this.width=width;
this.height=height;
this.color=color;
}
draw(){
console.log(`drawing ${this.color} color of`);
}
getArea(){
return this.width*this.height;
}
}
const parent_class = new shape(10,10,'black');
console.log(parent_class.draw()); //drawing black color of
console.log(parent_class.getArea()); //100
위의 코드는 앞으로 부모 클래스 역할을 할 클래스이다.
이제 이 shpae 클래스를 상속 받을 자식 클래스를 만들어보자.
class Rectangle extends shape()
const rectangle = new Rectangle(20,20,'blue');
rectangle.draw(); //drawing blue color of
console.log(rectangle.getArea()); //400
console.log(rectangle.width); //20
이번에는 Rectangle 이라는 클래스를 선언하면서 extends로 부모 클래스(shape)를 상속 받는다. 자식 클래스(Rectangle)는 별도의 객체 선언이 없어도 부모로부터 상속받은 함수, 변수들을 그대로 사용할 수 있다.
오버라이딩(Overriding)
자식 클래스가 부모 클래스들 중 하나에 의해 이미 제공된 함수 등을 특정 형태로 구현하는 것
부모 클래스에서 이미 정의된 함수 등을 자식 클래스에서 같은 이름으로 사용하되 안에 있는 내용(기능. 속성 등)을 바꿔서 사용한다고 생각하면 된다.
흔히 부모와 자식 사이에서 형제들이 유전적으로 물려받는 부분은 같아도 어떻게 먹고, 어떻게 자고, 어떻게 생활하냐에 따라 키, 외모, 공부 성적 등이 달라지듯 자식 클래스도 상속 받은 부모 클래스의 기능들을 어떻게 바꿔서 사용하는지에 따라 그 기능이 달라지게 된다. 그것을 프로그래밍에서는 Overriding(오버라이딩)
이라고 한다.
부모 클래스 버전을 사용할 것이냐, 자식 클래스 버전을 사용할 것이냐는 호출되었을 때 사용되는 객체에 따라 달라지게 된다. 만약 부모 클래스의 객체가 함수를 발생시키는데 사용된다면 부모 클래스 버전이 실행되고, 자식 클래스의 객체가 함수를 발생시키는데 사용된다면 자식 클래스 버전이 사용될 것이다.
class Triangle extends shape {
// overiding
draw() {
super.draw();
console.log('🔺');
}
getArea() {
return (this.width * this.height) / 2;
}
// Object를 상속받았기 때문에 toString을 사용할 수 있음
toString() {
return `Triangle: color: ${this.color}`;
}
}
const triangle = new Triangle(20, 20, 'red');
triangle.draw(); // drawing red color of 🔺
console.log(triangle.getArea()); // 200
console.log(triangle.toString()); // Triangle: color: red
위에서 작성했던 Rectangle 클래스(자식 클래스)와는 다르게 Triangle 클래스(자식 클래스)는 shape 클래스(부모 클래스)를 상속받고 내용을 작성했다. 부모 클래스에서 이미 작성되어있는 draw( ) 함수를 다시 작성했다.
drawing ${this.color} color of
);" 이다. 따라서 자식 클래스의 draw( ) 함수를 호출하면 console.log(drawing ${this.color} color of
);
console.log('🔺');
를 차례로 호출해 " drawing red color of 🔺"를 출력한다.
toString( ) 은 이미 javascript에 정의되어 있는 함수이다. 모든 클래스는 javascript에서 이미 정의된 object 클래스(toString( ) 등)를 상속받는다. 따라서 이 toString( ) 함수도 Overriding 했다고 할 수 있다.
자식 클래스에서 super 함수는 부모 클래스를 의미하며, 부모 클래스의 생성자에 인수를 전달한다. 공통되는 속성은 부모 클래스의 것을 사용하고, 공통되지 않는 속성은 자식 클래스에 따로 선언한다.
메서드에서도 super를 사용할 수 있다. 자식 클래스에서 super.메서드를 호출하면 이것은 부모 클래스의 메서드를 호출하는 것과 같다. 부모 클래스의 메서드를 호출한 후 다른 동작ㅇ르 할 수 있다. 자식 클랙스에 메서드를 생성하지 않은 경우에도 부모 클래스에 메서드가 존재한다면 호출할 수 있다.
상속은 클래스를 사용하는데 편의성을 더해준다. 같은 코드를 반복해서 사용하지 않고 클래스를 상속해서 사용하기 때문에 효율적이다.
Class checking: instanceOf
instanceOf는 A가 B의 instance인지 등에 대해 확인할 수 있는 연산자이다.
인스턴스(instance)는 객체 지향 프로그래밍에서 해당 클래스의 구조로 컴퓨터 저장공간에서 할당된 실체를 의미합니다.
위에서 사용된 클래스들을 이용해 아래와 같이 코드를 작성했다.
console.log(rectangle instanceof Rectangle); // True
console.log(triangle instanceof Rectangle); // False
console.log(triangle instanceof Triangle); // True
console.log(triangle instanceof shape); // True
console.log(triangle instanceof Object); // True
문제
Human 클래스를 상속하면 조금 더 구체적인 사람을 만들 수 있다. HTML, CSS, JS를 할 줄 아는 개발자를 만들어 보자.
class Human {
constructor(name,age) {
this.name = name;
this.age = age;
}
sayName(){
console.log(this.name);
}
sayAge(){
console.log(this.age);
}
}
정답
class Human {
constructor(name,age) {
this.name = name;
this.age = age;
}
sayName(){
console.log(this.name);
}
sayAge(){
console.log(this.age);
}
}
class Developer extends Human {
constructor(name,age,languages) {
super(name,age);
this.languages = languages;
}
sayLanguages(){
console.log(this.languages.join()+'(으)로 코딩해요.');
}
}
const developer = new Developer(
'hannah',
27,
['html','css','js'],
);
developer.saylanguages(); //html, css, js,(으)로 코딩해요.