[javascript] prototype과 prototype chain

Hyebin·2021년 4월 15일
0

Javascript

목록 보기
22/27
post-thumbnail

OOP란 개념을 배웠는데 자바스크립트에서는 OOP를 어떻게 구현할 수 있는지 알아보자.
자바스크립트는 클래스란 개념이 없어 프로토타입이란 매커니즘을 통해 OOP를 구현할 수 있다. 이 프로토타입 중에서도 상속을 통한 프로토타입 체인이란 개념이 중요하다.

프로토타입(prototype)

프로토타입을 한마디로 정의하면 "원형 객체"이다.

prototype을 이용해 새로운 객체를 만들어 낼 수 있다.
prototype을 통해 만들어진 객체는 prototype 객체의 속성들을 물려받게 된다.

function Person(name, age) {
  this.name = name;
  this.age = age
}

let me = new Person('meme', 10);

프로토타입 체인(Prototype chain)

prototype 객체는 기본적인 속성으로 constructor__proto__를 가지고 있다.
이 중 __proto__에는 자식의 부모 prototype 객체를 가리키는 링크를 담고 있다.

프로토타입 체인은 __proto__의 특징을 이용하여, 부모 객체의 프로퍼티나 메서드를 차례로 검색하는 것을 의미한다.
이 말의 의미는 특정 객체의 프로퍼티나 메서드 접근시 자신의 것 뿐 아니라 부모 객체의 것도 접근해서 사용가능하다는 것이다.

모든 프로토타입 체이닝의 종점은 Object.prototype이다.
Object는 가장 상위 객체이다. (모든 객체의 부모격)

아래는 Human이란 클래스에 생성자 함수와 sleep(), eat()메소드를 정의해줬다.

class Human {
 	constructor(name, age) {
      this.name = name;
      this.age = age;
    }
  
  sleep() {
    console.log(`${this.name}이 자고 있어요.`);
}
  eat(food) {
    console.log(`${this.name}${food}를 먹고 있어요.`);
}

new 키워드로 생성자 함수를 불러서 jumi라는 인스턴스를 생성하게 되면
jumi는 name과 age 프로퍼티를 갖는 객체인데 sleep()이나 eat()메서드를 쓸 수 있다.

let steve = new Human('steve', 20);

steve;  // { name: 'steve', age: 20} 

steve.sleep();  //steve이 자고 있어요.
steve.eat(apple);  //steve이 apple를 먹고 있어요.

이유는 __proto__에 부모 객체인 Human의 링크를 담고 있어 부모 메서드를 불러다 사용하기 때문이다.

Human 클래스와 프로토타입과의 관계를 살펴보면 보면

  • 모든 function에는 프로토타입 속성이 있다.
    Human.prototype에 sleep()메서드가 있다.
  • 인스턴스를 생성하는 과정을 instantiation이라 한다.
    new 키워드로 인스턴스를 생성한다.

assignable prototyle?

프로토타입은 할당이 가능하다.

유사 배열을 만들고 싶을 때 Array의 프로토 타입을 할당해주면 배열처럼 작동해서 배열의 메서드들을 쓸 수 있다.

상속

자신과 부모 프로토타입을 체인닝 할 수 있는 2가지 방법이 있다.

만약 위의 예시 처럼 Human 클래스를 만들고, Student라는 클래스를 하나 더 만들어 jumi라는 인스턴스를 생성한다고 할 때, jumi는 Student의 속성과 메서드만 사용할 수 있다.

이때, jumi는 학생이면서 사람이기도 하기때문에 Human의 속성과 메서드도 사용하고 싶다면 어떻게 가져다 쓸 수 있을까??

1) psudoclassical

고전적인 방법으로 체인닝의 원리를 이해하는데에 의의를 두자 ㅎㅎ
ES6와서는 잘 쓰이지 않는 방법이다.

const Human = function(name, age) {
  this.name = name;
  this.age = age;
}

//메서드 
Human.prototype.sleep = function() {
  console.log(`${this.name}이 자고 있어요.`);
}

Human.prototype.eat = function() {
    console.log(`${this.name}${food}를 먹고 있어요.`);
}
const Student = function(name, major) {
  this.name = name;
  this.major = major;
}

Student.prototype.study = function() {
  console.log(`${this.name}${this.major}를 공부하고 있어요.`);
}

let jumi = new Student('jumi', 'English');

jumi;  //{name: 'jumi', major: 'English'}
jumi.study();   // jumi이 English를 공부하고 있어요.
jumi.sleep();   // VM599:1 Uncaught TypeError: jumi.sleep is not a function

위 처럼 sleep()을 써주면 Student에 메서드로 정의되지 않았기 때문에 에러가 난다.

Student.prototype에 Human.prototype을 할당해주면 메서드를 사동할 수 있을지 봐보자.

sleep()을 쓸 수 있다. 하지만 이렇게 할당하게 되면 객체의 참조를 바꿔버리게 된거라 Human을 바라보게 되면서 Student의 메서드였던 learn()을 쓸 수 없다.

Student.prototype = Human.prototype;

jumi.sleep();	// jumi이 자고 있어요.
jumi.study();  // VM1195:1 Uncaught TypeError: jumi.study is not a function

Object.create()를 써서 Human.prototype을 카피한 것을 Student.prototype에 할당해주면 된다.

Student.prototype = Object.create(Human.prototype);

이렇게 카피한 것을 참조하도록 할당하게 해주면 두가지 추가 작업을 해줘야 제대로 된 체이닝이 된다.

  • 약해진 체이닝 고리 Student로 다시 이어주기
    constructor를 보면 Human을 바라보는데 이것을 Student로 다시 바꿔줘야 한다.
  • Human this에 인스턴스 속성 전달하기
const Student = function(name, major) {
  //Human에 this
  Human.call(this, name);
  this.name = name;
  this.major = major;
}

Student.prototype = Object.create(Human.prototype);
// constructor를 Student로 바꿔줌
Student.prototype.constructor = Student;

Student.prototype.study = function() {
  console.log(`${this.name}${this.major}를 공부하고 있어요.`);
}

2) ES6

ES6에서는 class란 새로운 개념이 등장하면서 부모를 상속받아 쓸 수 있게 되었다.

자식 클래스를 생성할 때 extends로 부모 클래스를 상속받는다.
부모에 this로 전달할 때는 super()를 써며, 이 super()this보다 위에 위치해야 한다.

class Human {
  constructor(name) {
    this.name = name;
  }
  
  sleep() {}
}

class Student extends Human {
  constructor(name, age) {
    super(name); //부모에 this로 전달 
    this.name = name;
    this.age = age;
  }
  study() {}
}  

1개의 댓글

comment-user-thumbnail
2022년 4월 2일

안녕하세요~ 좋은 글 잘 읽고 갑니다 :)

완전 이해가 잘되네요~ 감사합니다아

"Student의 메서드였던 learn()을 쓸 수 없다." 이 문장에 오타가 있는 것 같은데 learn()이 아니라 study()인 것 같아요 :)

답글 달기