JS의 Prototype을 이용한 객체지향 상속 구현과 ES6 class의 상속 구현

유자·2020년 10월 31일
0

Prototype Chain


__proto__, constructor, prototype 의 관계

자바스크립트에서 함수를 정의하면 함수만 생성되는 것이 아니라 Prototype Object도 같이 생성된다.

때문에 모든 함수는 prototype이라는 속성을 가진다.(함수명.prototype을 콘솔창에 입력해보면 확인가능)
이 prototype은 assgin 가능하기 때문에, 이 능력을 통해 객체지향프로그래밍의 상속 이 구현 가능해진다.
prototype 객체의 key는 constructor, __proto__ 두 가지가 있다.
각 key에 해당하는 value는 순서대로 생성자 함수, 부모의 prototype이 있다.

  • prototype : 모델의 청사진을 만들 때 쓰는 원형 객체(original form)
  • constructor : 인스턴스를 만들어내는 생성자 함수
  • this : 함수가 실행될 때, 해당 scope 마다 생성되는 고유한 실행 context(execution context). new 키워드로 인스턴스를 생성했을 때에는, 해당 인스턴스가 바로 this의 값이 됨

prototype 객체에는 속성이나 메소드를 정의할 수 있다.

class Car { //Car.prototype = {constructor: f, dirve: f}
  constructor(color, brand) {
    this.color = color; //consturctor 안에 속성 정의
    this.brand = brand;
  }
  drive() { //메소드 정의
    console.log(`I\'m on ${this.brand}`)
  }
}

인스턴스를 생성하는 것을 instantiation이라고 한다 -> let mine = new Car;

mdn에서 배열 메소드를 검색해볼 때, Array.prototype.method.. 를 보았을 것이다.
이것은 Array라는 최상위 객체(Array.prototype)에 메소드를 정의함으로써 하위 array들이 해당 메소드를 사용할 수 있도록 한 것임을 알 수 있다.

이와 마찬가지로 Object.prototype이라는 객체에도 다양한 메소드가 저장되어 있으며, 이 객체는 모든 객체의 가장 최상위 객체이다.

그럼 어떻게 prototype의 상위 객체, 상위 객체 위의 상위 객체, 최상위 객체 등을 구현할 수 있는 것인가!
바로 prototype객체 안에 있는 __proto__ 덕분이라고 할 수 있다.
__proto__는 부모객체를 연결시켜놓는 역할을 함으로써 prototype chain을 구현한다.

또한 prototype은 할당이 가능하기 때문에, 가짜 배열을 만들고 싶다면 아래와 같이 구현 가능하다.

let FakeArray = function() {
}

FakeArray.prototype = Array.prototype;

let fakeArray = new FakeArray();

//fakeArray.push(1);
//fakeArray[0] === 1 
//위와 같이 가짜 배열에 배열 메소드 사용 가능

Object.create 메소드는 pseudoclassical에서 상속을 구현하기 위한 방법이다.

pseudoclassical 이란 자바스크립트에 class 라는 함수가 추가되기 이전에 객체지향을 구현하기 위해 사용된 방식이다.

  1. Object.create(부모객체.prototype);
    Object.create 함수는 첫번째 인자(=부모 객체)로 들어가는 prototype 을 바탕으로 새로운 prototype을 만든다. like copy.

  2. 자식객체.prototype = Object.create(부모객체.prototype);
    copy된 prototype을 자식의 prototype에 할당한다.

  3. 이 방법으로 연결시켜주게되면 자식 객체와 constructor의 연결 고리가 끊어지게 된다. 카피된 prototype을 연결함으로써 constructor의 연결고리까지 같이 카피된 것이 적용되기 때문이다.
    이를 해결해주기 위해서는(=상속을 정확하게 만들기 위해서는)
    자식객체.prototype.constructor = 자식객체 를 추가해 끊어진 고리를 다시 연결시켜줘야 한다.

  4. 여기서 끝이 아니다. instance를 생성하려면 new 키워드를 사용하게 되는데, 자식 객체의 this 맥락이 상속된 부모 객체까지 전달이 안된다.
    이를 전달해주기 위해서는 자식객체에서 바인딩되는 this 맥락을 부모객체까지 올려보내줘야 한다. 이는 아래와 같이 구현 가능하다.
    부모객체.call(=apply)(this, arguments)를 자식객체 생성 함수에 작성한다.


ES6의 class, super의 이용방법

pseudoclassical의 복잡한 과정을 쉽게 만든 것이 class!

상속은 extends로 구현하고 constructor는 생성함수, this 맥락을 전달해주는 부분은 super라는 키워드로 추가했다.

super는 this의 맥락 전달 뿐만 아니라 부모 객체의 함수를 호출할 때도 사용이 가능하다.

class Animal {
    constructor(name) {
      this.name = name;
    }
    sleep() {
        console.log(`${this.name} is sleeping zZ`);
    }
}

let siba = new Animal('siba');

class Dog extends Animal { //extends 로 Animal을 Dog에 상속 
    constructor(name) {
        super(name); //this의 맥락을 부모 객체와 공유
        this.name = name;
    }
    bark() {
        console.log(`${this.name} is barking !`);
    }
}

let jindo = new Dog('jindo');
jindo.sleep(); //jindo is sleeping zZ
jindo.bark();  //jindo is barking !

참고

profile
No one left behind

0개의 댓글