prototype으로 class상속 구현하기👩‍👦

junamee·2021년 8월 4일
3

자바스크립트

목록 보기
3/11

👉포로토타입 형식의 자바스크립트에서 클래스 상속을 구현하기

-> 프로토타입 체이닝을 이용한 것
-> 체이닝의 조건

1. 상속받을 생성자함수(하위 클래스)의 prototype이 상속할 생성자함수(클래스)의 prototype(메서드)을 참조하도록 연결하기

: 상위함수의 프로토타입 메서드를 사용할 수 있도록
인스턴스.__proto__=상위생성자함수.prototype
하위생성자함수.prototype=상위생성자함수.prototype

*프로토타입 메서드와 인스턴스 메서드
: 프로토타입 메서드는 하위 생성자함수에 상속(참조)가 가능한 메서드이고, 인스턴스 메서드는 생성자함수로 생성한 구체적인 인스턴스에 직접 정의한 메서드여서 해당 인스턴스에서만 사용할 수 있고 참조, 상속이 불가능하다. 여기서 상속하는 메서드는 모두 프로토타입 메서드이다.

2. 상속받을 생성자함수(하위 클래스)의 prototype에 상속할 생성자함수(상위 클래스)의 인스턴스가 부여되지 않도록 하기

: 상속을 구현하기 위해 일반 객체를 하위클래스의 틀로 사용하고 있는데, 일반 객체이기 때문에 내부 프로퍼티를 삭제할 수 있는 환경이다. 만약 상속받을 생성자함수의 내부 프로퍼티를 삭제하게 된다면 메서드 실행 시, 필요로하는 프로퍼티가 없으므로 __proto__를 타고 상위 생성자함수를 탐색하게 되고 만약 상위 생성자함수 내부에 동일한 이름의 프로퍼티가 존재한다면 그 프로퍼티를 하위 생성자함수에서 사용하게 된다.

이 부분에서 클래스 상속을 구현하는 방법이 3가지로 구성된다.
1) 상위인스턴스의 프로퍼티를 삭제
2) 상위생성자함수의 프로토타입을 속성으로 갖는 새로운 객체 생성하여 하위 클래스와 연결해주기 : Object.create()
3) 빈 함수에 상위생성자함수의 프로토타입을 연결하여 하위클래스에 연결

3. 상속받는 생성자함수(하위 클래스)의 constructor가 상속한 생성자함수(상위 클래스)를 가르키지 않고 본인의 생성자함수를 가르키도록 하기

subClass.prototype.constructor = subClass

Object.create(proto[, properties])

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메서드를 볼 수 있다.

프로토타입을 위와 같은 구조를 갖는 클래스 상속을 구현해보자.

step1. 하위생성자함수가 상위생성자함수를 참조하게 만들자 (순서 주의)

이때 주의할 점은 하위생성자함수 메서드의 정의보다 상/하위생성자 함수간의 연결을 먼저 해주어야 한다는 것이다. 만일, 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를 찾아볼 수가 없다.

step2. 메서드 분리를 위해 상위생성자함수의 속성을 갖는 새로운 생성자함수를 만들어 연결하자

myDog.prototype=Dog.prototype 대신에 아래와 같이 작성하기
prototype 연결이 아닌 Object 연결!

myDog.prototype = Object.create(Dog.prototype)  
  //<- *Dog의 프로토타입을 속성으로 갖는 새로운 객체를 연결해주었다.

클래스형태와 조금 더 가까워졌다.
Dog을 참조하며 myDog의 프로퍼티로 introduce2를 갖고있으며
instance.__proto__.__proto__로 introduce메서드를 참조하고있음을 확인할 수 있다.
이제 그 다음으로는 undefined 를 해결해야한다.

step3. this 연결해주기

myDog에서 this.size를 인식하고 있지 못한 상태이다.
상위 함수 Dog에서 this.size를 myDog에 전달해주자.

function myDog(size, kind){
  Dog.call(this, size); //call은 바로 실행되어 this.size=size가 된다.
  this.kind=kind;
}

step4. constructor 정해주기

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를 자기 자신으로 정의함으로써 상속을 구현할 수 있다.

profile
아티클리스트 - bit.ly/3wjIlZJ

0개의 댓글