Dev/SW Engineering

9. Inheritance Patterns - Pseudoclassical Inheritance

HJChung 2020. 6. 11. 09:21

상속이란

상속(Inheritance)는  부모(Basic class)의 속성을 물려받는 것을 말합니다. 

상속의 필요성

  • 상속을 통해서 중복되는 코드를 부모코드가 제공하고 자식코드는 제공받습니다. 이를 통해 
  • 코드의 양도 줄이면서
  • 부모 코드에 해당하는 부분이 수정되어야 하는 경우, 자식 코든는 하나씩 변경할 필요없이 동시에 변경이 되므로 유지, 보수에 편리합니다. 

상속 방법

1) class를 통해서 상속하는 방법

주요 객체지향언어는 subclass가 superclass의 자식이 되고, 그렇게 자식이 된 subclass에서 객체(object)를 만들어낸다. 그림으로 나타내면, 

이런 방식을 통해서 생성된 객체의 성질은 class로부터 이미 정해져 있습니다. 

 

2) 객체를 통해서 상속하는 방식 

JavaScript는 객체가 직접 다른 객체를 상속받을 수 있고 얼마든지 prototype link를 통해서 상속 받을 부모 객체를 다른 객체로 바꿀 수 있습니다. ES6에서 Class문법을 볼 수 있지만 이는 Class개념을 흉내낸 것 JavaScript가 Class 기반 언어처럼 작동하게 바뀌었다는 것은 아닙니다. 정리하자면, Class 개념이 없는 JavaScript는 Prototype을 기반으로 상속을 흉내 내도록 구현해서 사용합니다. 

상속의 구현

Human이 부모 object, Student는 자식 object를 구현해보고자 합니다. 

var Human = function(name){
	this.name = name;
}

Human.prototype.sleep = function(){};

let steve = new Human('steve');

var Student = function(name){
}

Student.prototype.learn = function(){};

var john = new Student('john');
john.learn();
john.sleep();

먼저 위의 코드까지는 아래와 같은 구성이 됩니다. 

 

 

 

 

 

 

 

 

 

 

Q1.

이때, Student가 Human을 상속받어서 Human이 부모 object, Student는 자식 object으로 연결해주는 방법은 무엇일까요?

A1.

 Human.prototype을 copy한 것을 Student.prototype에 넣으면 어떨까? (여기서 copy는 JavaScript에서 prototype of라고 생각해주면 쉽습니다. 즉, Prototype of Human.prototype을 Student.prototype에 넣어주면 어떨까? 와 같은 말입니다. )

이렇게 해 주는 method가 바로 Object.create(proto)입니다. 

Object.create()는 첫 번째 parameter로 들어가는 prototype 객체를 바탕으로 prototype을 만든다. 는 것인데 그냥 쉽게 생각해서 첫 번째 parameter로 들어가는 prototype을 copy해서 이를 참조하게 한다. 로 생각하면 됩니다. 

Student.prototype = Object.create(Human.prototype);
Student.prototype.learn = function(){}

 

 

Q2.

그런데

Student.prototype = Object.create(Human.prototype);
Student.prototype.learn = function(){}
var john = new Student('john')

여기 까지 한 후 john.__proto__.constructor을 콘솔창에 쳐보면 Student가 아니라 Human으로 나오는 문제가 있습니다. 

A2.

그래서 constructor을 올바르게 연결해주려면 한 번 더 아래와 같이 명시해주는 것이 필요합니다 

Student.prototype.constructor = Student;

Student.prototype.constructor = Student;

 

 

 

 

 

Q3.

new 키워드를 쓰면 this는 instance가 되는데 Student의 this도 john, Human의 this도 john이 되어야 하는데 Human의 this까지 context가 올라가질 않아 Human의 this는 undefined가 됩니다. 

A3. 

그래서 .call 또는 .apply을 사용해서 Human의 this에 올려주어야 합니다. 

var Student = function(name){
	Human.call(this, name);
}
Student.prototype = Object.create(Human.prototype);
Student.prototype.constructor = Student;

그러면 최종적으로

출처: codestates

이렇게 잘 상속되어 Human이 부모 object, Student는 자식 object으로 구현된 Student instance인 john이 만들어짐을 알 수 있습니다. 

 

상속 및 다형성의 구현

상속을 받은 것에 추가로 뭘 더 해주고 싶다 -> 이런게 바로 다형성으로 이어지게 되는데요, 어떻게 구현해 줄 수 있을까요

예를 들어) 

function Human(name){
	this.name = name;
}

function Student(name){
	Human.apply(this, argument)
}

Human.prototype.sleep = function(){
	console.log("자되 되는데, ");
}

Student.prototype.sleep = function(){
	console.log("4시간만 자야함");
}

Q4.

이런 코드가 있다고 할 때, Student.prototype.sleep을 실행하면 Human.prototype.sleep의 "자도 되는데"와 Student.prototype.sleep의 "4시간만 자야됨"이 둘 다 실행되길 원한다면? 

A4. 

Student.prototype.sleep 메소드 내에 Human.prototype.apply(this) (or Human.prototype.call(this))를써주면 됩니다. 

이렇게 해주면 두 메소드가 같은 context를 공유하게 됩니다.

 

Class Inheritance

Pseudoclassical Inheritance는 너무 복잡합니다. ES6에서 Class문법을 사용해서 상속을 할 수 있는 방법이 있습니다. 

  • Human.prototype.apply(this) (or Human.prototype.call(this)) 
    => Super(_)로 해결
  • Object.create(proto), Student.prototype.constructor = Student; 등으로 연결 
    => extends 키워드로 해결

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Reference

https://poiemaweb.com/js-prototype

 

Prototype | PoiemaWeb

자바스크립트의 모든 객체는 자신의 부모 역할을 하는 객체와 연결되어 있다. 그리고 이것은 마치 객체 지향의 상속 개념과 같이 부모 객체의 프로퍼티 또는 메소드를 상속받아 사용할 수 있게

poiemaweb.com