객체 지향 프로그래밍에서 '상속'이라는 특성을 구현할 때는 프로토타입 체인을 이용한다. 예를 들어 People이라는 클래스가 있다고 생각해보자.
class People {
constructor(name, age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
}
그리고 해리포터를 생각하고 Wizard라는 클래스도 만들었다. 그런데 이 때, 사실 Wizard라는 클래스는 People이라는 클래스가 가진 속성을 상속받을 수 있다. Wizard는 마법사이기 전에 먼저 사람이기 때문이다. (그냥 단순히 상속을 받아야 하는 관계라 생각한다.) Wizard는 사람의 속성을 물려받고, 추가로 마법이라는 속성이 필요하다.
class Wizard {
constructor(name, age, gender, magic) {
this.name = name;
this.age = age;
this.gender = gender;
this.magic = magic}
}
Wizard는 People의 특징을 그대로 물려받는다. 이렇게 속성과 메서드를 물려주는 클래스를 부모 클래스(여기서는 People), 속성과 메서드를 물려받는 클래스를 자식 클래스(여기서는 Wizard), 그리고 이 과정을 상속이라고 한다.
이를 extends 와 super 키워드를 이용해서 더 간편하게 구현할 수 있다. super 키워드를 이용하면 부모의 속성과 메서드 모두 가져올 수 있다.
class Wizard extends People {
constructor(name, age, gender, magic) {
super(name,age, gender);
this.magic = magic}
}
이 때, 같은 프로퍼티가 있다면 새롭게 작성된 프로퍼티가 super로 불러온 프로퍼티를 덮어 쓴다.
class Wizard extends People {
constructor(name, age, gender, magic) {
super(name,age, gender);
this.magic = magic;
this.name = '안녕핫요';
}
}
const harry = new Wizard ('harry', 15, 'M', 'alohomora');
console.log(harry.name) // '안녕핫요';
또한, super는 반드시 this의 앞에 와야한다. 그러지 않을 경우 SyntaxError가 발생한다.
우선, 모든 클래스의 부모는 Object임을 항상 기억한다.
위의 코드를 이용해 인스턴스를 하나 만든다.
class Wizard extends People {
constructor(name, age, gender, magic) {
super(name,age, gender);
this.magic = magic}
}
const harry = new Wizard ('harry', 15, 'M', 'alohomora');
여기서 proto를 이용하면 부모를 찾아 올라갈 수 있다.
harry.__proto__;
harry.__proto__.__proto__;
harry.__proto__.__proto__.__proto__
;
첫 proto에서는 부모인 Wizard를 확인할 수 있고, 두번째에서는 Wizard에게 속성을 상속해준 People, 세번째에서는 모든 클래스의 부모인 Object를 확인할 수 있다. 이 결과에 따르면, 프로토타입 체인을 거슬러 올라가다보면 결국 Object가 나오고, 결국 Object는 모든 클래스의 부모가 된다. 따라서 자식관계인 harry 또한 Object의 프로토타입에 있는 메서드를 사용할 수 있는 것이다.
그러나 proto는 권장되는 방식이 아니다. Object.setPrototypeOf와 Object.getPrototypeOf가 proto 의 방식을 대체하게 되었기 때문에 proto의 사용을 지양한다.