-> 프로토타입 체이닝을 이용한 것
-> 체이닝의 조건
: 상위함수의 프로토타입 메서드를 사용할 수 있도록
인스턴스.__proto__
=상위생성자함수.prototype
하위생성자함수.prototype
=상위생성자함수.prototype
*프로토타입 메서드와 인스턴스 메서드
: 프로토타입 메서드는 하위 생성자함수에 상속(참조)가 가능한 메서드이고, 인스턴스 메서드는 생성자함수로 생성한 구체적인 인스턴스에 직접 정의한 메서드여서 해당 인스턴스에서만 사용할 수 있고 참조, 상속이 불가능하다. 여기서 상속하는 메서드는 모두 프로토타입 메서드이다.
: 상속을 구현하기 위해 일반 객체를 하위클래스의 틀로 사용하고 있는데, 일반 객체이기 때문에 내부 프로퍼티를 삭제할 수 있는 환경이다. 만약 상속받을 생성자함수의 내부 프로퍼티를 삭제하게 된다면 메서드 실행 시, 필요로하는 프로퍼티가 없으므로 __proto__
를 타고 상위 생성자함수를 탐색하게 되고 만약 상위 생성자함수 내부에 동일한 이름의 프로퍼티가 존재한다면 그 프로퍼티를 하위 생성자함수에서 사용하게 된다.
이 부분에서 클래스 상속을 구현하는 방법이 3가지로 구성된다.
1) 상위인스턴스의 프로퍼티를 삭제
2) 상위생성자함수의 프로토타입을 속성으로 갖는 새로운 객체 생성하여 하위 클래스와 연결해주기 : Object.create()
3) 빈 함수에 상위생성자함수의 프로토타입을 연결하여 하위클래스에 연결
subClass.prototype.constructor = subClass
proto를 갖는 객체를 새로 생성한다.
properties는 선택사항이며 추가 및 overide가 가능하다.
=>지정된 프로토타입과 속성을 갖는 새로운 객체 생성
아래는 클래스로 상속을 표현하였고, 상속받은 생성자함수로 만든 인스턴스의 구조를 파악할 수 있다.
class Dog {
constructor(size){
this.size = size
}
introuduce(){
return `This is ${this.size}size of dog`
}
}
class myDog extends Dog{
constructor(size, kind){
super(size, kind)
this.kind=kind;
}
introuduce2(){
return `this dog is kind of ${this.kind}`
}
}
const bbobbi = new myDog('빅','래브라도')
bbobbi.introuduce() //"This is 빅size of dog"
bbobbi.introuduce2() //"this dog is kind of 래브라도"
인스턴스 내부에는 kind, size
라는 프로퍼티를 확인할 수 있으며,instance.__proto__
는 상속을 한 Dog를 참조함이 보여진다.
그리고 instance.__proto__.constructor
는 자기 자신 myDog
생성자 함수를 가리키고 있는 상태이다. 메소드로는 자신의 메소드인 introuduce2
를 갖고있으며 instance.__proto__.__proto__
를 타고 가면 상속한 생성자 함수로부터 참조하고있는 introuduce
메서드를 볼 수 있다.
프로토타입을 위와 같은 구조를 갖는 클래스 상속을 구현해보자.
이때 주의할 점은 하위생성자함수 메서드의 정의보다 상/하위생성자 함수간의 연결을 먼저 해주어야 한다는 것이다. 만일, myDog.prototype=Dog.prototype
이 코드보다 myDog.prototype.introduce2
를 먼저 정의하고 연결을 하게 되면
myDog.prototype
자체를 Dog.prototype
로 재 정의함으로써 기존 메서드들이 덮여 씌워지고introduce2
메서드가 아예 존재하지 않는 값이 되버린다.
연결을 먼저해주고 myDog의 메서드를 추가해준다.
(override : 상속받은 부모의 메서드에 새로운 메서드를 추가(메서드명이 다른 경우)
혹은 재정의(메서드명이 동일한 경우))
function Dog(size){
this.size = size;
}
Dog.prototype.introduce = function(){
return `This is ${this.size} size of dog`
}
//*상속받을 프로퍼티 size를 미리 갖고요~
function myDog(size, kind){
this.kind=kind;
}
myDog.prototype=Dog.prototype //<- *순서주의!
myDog.prototype.introduce2 = function(){
return `this dog is kind of `+this.kind +` and`+this.introduce()+'!!!💖'
}
const wangja = new myDog('middle', 'jindo')
wangja.introduce() //"This is undefined size of dog"
wangja.introduce2() //"this dog is kind of jindo and This is undefined size of dog!!!💖"
하위 생성자함수 myDog이 상위 생성자함수 Dog의 프로퍼티를 참조하고있음을 확인할 수 있다.
introduce, introduce2 메서드 모두 소지!
만약 위의 주의사항처럼 순서를 반대로 선언했다면, 상위 생성자함수에 뒤덮혀 아래와 같이 introduce2를 찾아볼 수가 없다.
myDog.prototype=Dog.prototype
대신에 아래와 같이 작성하기
prototype 연결이 아닌 Object 연결!
myDog.prototype = Object.create(Dog.prototype)
//<- *Dog의 프로토타입을 속성으로 갖는 새로운 객체를 연결해주었다.
클래스형태와 조금 더 가까워졌다.
Dog을 참조하며 myDog의 프로퍼티로 introduce2를 갖고있으며
instance.__proto__.__proto__
로 introduce메서드를 참조하고있음을 확인할 수 있다.
이제 그 다음으로는 undefined 를 해결해야한다.
myDog에서 this.size를 인식하고 있지 못한 상태이다.
상위 함수 Dog에서 this.size를 myDog에 전달해주자.
function myDog(size, kind){
Dog.call(this, size); //call은 바로 실행되어 this.size=size가 된다.
this.kind=kind;
}
myDog.prototype.constructor = myDog
최종코드
function Dog(size){
this.size = size;
}
Dog.prototype.introduce = function(){
return `This is ${this.size} size of dog`
}
//*상속받을 프로퍼티 size를 미리 갖고요~
function myDog(size, kind){
Dog.call(this, size);
this.kind=kind;
}
myDog.prototype = Object.create(Dog.prototype)
myDog.prototype.introduce2 = function(){
return `this dog is kind of `+this.kind +` and`+this.introduce()+'!!!💖'
}
myDog.prototype.constructor = myDog
const wangja = new myDog('middle', 'jindo')
wangja.introduce() //"This is middle size of dog"
wangja.introduce2() //"this dog is kind of jindo andThis is middle size of dog!!!💖"
이렇게 하면 클래스와 동일한 구성을 갖는 상속을 구현할 수 있게 된다.
Object.create를 사용해서 구현했는데, 다음엔 property를 삭제하는 방법(myDog.prototype=Dog
으로 연결한 후의 Dog 프로퍼티를 삭제), 비어있는 함수를 상위클래스 프로퍼티로 연결하여 쓰는 방법도 시도해보려고 한다.
예전에 공부한 내용이어도 이해하는데 오랜 시간이 걸렸다.
계속 반복하다보면 쉽게 할 수 있겠지!?
prototype으로 클래스 상속은 어떻게할까?
메서드 체이닝을 이용해서 상하위 생성자함수간의 메서드를 참조할 수 있도록 해야한다.
이 때 Object.create를 사용해서 상위 생성자함수의 속성을 갖는 새로운 객체를 생성한 후 하위 생성자함수와 연결을 해주고, 상위 생성자함수의 프로퍼티를 인지할 수 있도록 this를 연결해준다.
마지막으로 실행자 constructor를 자기 자신으로 정의함으로써 상속을 구현할 수 있다.