[Javascript] 프로토타입 상속이란?

2020. 10. 2. 00:14Frontend

Interview Section은 FrontEnd Interview Question에 대한 QnA를 다룹니다.

 

 

https://dottedsquirrel.com/javascript/understanding-prototypes-in-javascript/

 

Q. Explain how prototypal inheritance works.

 

 

A.

 

자바스크립트는 자바와 같은 일반적인 객체지향(이하 OOP) 언어들과는 다르게 "프로토타입 기반 언어"입니다. 따라서 클래스라는 개념이 없고(ES6에서 클래스를 도입하긴 했지만, 엄밀히 따지면 자바의 클래스 개념과는 많이 다른, 그저 Syntax Sugar에 지나지 않음), 이를 프로토타입을 통해 해결하려 합니다. 

 

 

OOP에서 상속이라는 개념은 부모 클래스의 속성(property)들을 자식 클래스에서 재선언할 필요 없이(오버라이드를 통해 재정의하는 것을 제외하고) 그대로 사용하는 것을 의미합니다. 앞서 언급했듯, 자바스크립트에서는 이를 프로토타입을 이용해서 해결합니다. 예시를 위해 다음과 같이 Person이라는 함수를 만들고 이 함수의 프로퍼티를 상속받는 Student라는 함수를 만들어서 Student의 인스턴스를 생성해보겠습니다. 구현은 다음과 같습니다.

 

 

 

함수와 프로토타입 상속을 이용해서 구현한 예제.

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

function Student(name, age, grade) {
  Person.call(this, name, age);
  this.grade = grade || 'F';
}

Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

const kim = new Student('kim', 20, 'A');
console.log(kim);

 

 

자바스크립트에서 함수가 선언되면, 함수의 원형을 가리키는 프로토타입 객체와, new 키워드를 통해 인스턴스를 생성할 수 있는 constructor객체가 생기게 됩니다. 

 

 

Student함수가 Person의 프로토타입을 상속받기 위해서는 다음과 같은 과정을 거칩니다.

 

1. Student함수 내에서 Person함수를 call하여 Person객체를 리턴받는다. 이때 call함수를 사용한 이유는 Student함수의 this를 바인딩해주기 위함입니다.

 

 

2. Student의 프로토타입 객체를 Person의 프로토타입 객체로 설정해줍니다. 이렇게 하는 이유는, Student의 프로토타입 객체를 Object가 아닌 Person으로 잡아줌으로써, Student가 Person을 상속받았음을 프로토타입 체이닝을 통해서도 알 수 있도록 하기 위함입니다. 이 과정을 생략하게 되면, Student의 __proto__ ([[Prototype]]) 이 가리키게 되는 객체는 Person이 아닌 Object입니다.

 

 

3. Student의 프로토타입 객체가 참조하는 Constructor도 Student로 만들어줌으로써, 망가진 순환참조를 복원시켜줍니다. 이렇게 하는 이유는 Student의 __proto__ 객체가 참조하는 Constructor는 Student가 되어야 하는 것이 자바스크립트의 프로토타입 체이닝 원칙이기 때문입니다. 

 

 

 

ES6에서 도입된 클래스 문법을 사용한 예제

class Person {
  constructor(name, age) {
    this.name = name || "Person";
    this.age = age || 30;
  }
}

class Student extends Person {
  constructor(name, age, grade) {
    super(name, age);
    this.grade = grade || "F";
  }
}

const kim = new Person("kim", 20);
console.log(kim);

const park = new Student("park", 20, "A");
console.log(park);

 

위의 두 구현은 자바스크립트 상에서는 동일한 구현입니다. 다만, ES6에서 구현하는 클래스 문법이 조금더 기존 객체지향문법(JAVA등)과 비슷해서 익숙하게 느껴질 수 있습니다. 

 

 

이렇게 프로토타입을 이용해서 상속하는 방식은 편리하고, 메모리를 절약할 수 있다는 장점이 있으나, 부모의 프로토타입에 대해서 복사본이 아닌 참조를 저장하게 되므로, 부모 프로토타입의 속성이 바뀌게 되면, 이를 상속받은 모든 자식들에게도 영향을 미친다는 단점과, 또 지나치게 깊은 상속이 이루어질 경우, 자바스크립트가 이 참조를 계산하는데에 시간을 낭비하여 퍼포먼스의 문제로 이어질 수 있다는 단점이 있습니다.

 

 

이를 해결하기 위한 다른 방법으로는 연결형 상속(Concatenative Inheritance) 및 함수형 상속(Functional Inheritance)가 있습니다. 이 방법은 자바스크립트 클로저(Closure)와 밀접한 연관이 있으며, 프로토타입을 참조하는 방식이 아닌 Object.assign()을 사용하여 복사하는 방식을 사용합니다. 

 

 

Reference

developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain

 

상속과 프로토타입

Java 나 C++ 같이 클래스 기반의 언어를 사용하던 프로그래머는 자바스크립트가 동적인 언어라는 점과 클래스가 없다는 것에서 혼란스러워 한다. (ES2015부터 class 키워드를 지원하기 시작했으나, ��

developer.mozilla.org

 

반응형

'Frontend' 카테고리의 다른 글

[Javascript] 함수 호이스팅  (0) 2020.10.03
[Javascript] null vs undefined  (0) 2020.10.03
[Javascript] Attribute vs Property  (1) 2020.09.29
[Javscript] 함수 스코프 vs 블록 스코프  (0) 2020.09.29
[Javascript] 클로저란?  (0) 2020.09.28