[JavaScript] 프로토타입

Jun·2022년 6월 11일
0

JavaScript

목록 보기
11/13
post-thumbnail

프로토타입 (prototype)

JavaScript는 흔히 프로토타입 기반 언어(prototype-based language)라고 부른다.

여기서 프로토타입은 원형 객체를 의미한다.

클래스의 새로운 인스턴스가 만들어질 때 상속되는 속성과 메소드들은 각 인스턴스에 새롭게 만들어져 저장되는 것이 아닌 클래스의 prototype 속성 객체에 저장된다.

class Human {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  
  sleep() {
    console.log(`${this.name} is sleeping now...`);
  }
}

먼저 Human 클래스를 만들었다. 이 클래스를 개발자 콘솔에서 console.dir() 로 확인해보자.

console.dir(Human)

Human 클래스의 멤버 변수lengthname 은 확인 가능하지만 sleep 메서드는 찾아볼 수 없다.

🎯 여기서 잠깐!
멤버 변수(혹은 데이터 멤버 / 클래스 필드)란?
클래스 내부의 캡슐화된 변수를 말한다. 쉽게 말해, 자바스크립트의 생성자 함수에서 this 에 추가한 속성(property)를 클래스 기반 객체지향 언어에서는 멤버 변수라고 부른다.

name 멤버 변수 바로 다음의 prototype 객체가 보이는가? 저것이 바로 프로토타입 객체이다.

조금 더 자세히 살펴보자.

prototype 객체 안에서 생성자 함수 constructorsleep 메서드가 존재함을 확인 할 수 있다.

인스턴스(자식 객체)는 클래스(부모 객체)의 prototype 객체를 참조하여 속성과 메서드를 사용할 수 있다.

인스턴스를 하나 만들어보자.

const student = new Human('David', '21');

해당 인스턴스를 확인해보면 다음과 같이 나타난다.

멤버 변수인 agename 은 보이지만 클래스에 존재하던 sleep 메서드는 보이지가 않는다.
위에서도 말했듯이 상속되는 속성과 메서드들은 인스턴스 객체 내부가 아닌 클래스의 prototype 에 저장된다.
[[Prototype]] 를 확인해보자.

클래스의 prototype 객체에 저장돼있는 constructorsleep 을 확인할 수 있다.

prototype 속성과 [[Prototype]]

객체는 자신의 프로토타입을 가리키는 [[Prototype]] 인터널 슬롯을 가지며 이것은 상속을 위해 사용된다.

함수 또한 객체이므로 [[Prototype]] 인터널 슬롯을 가진다. 하지만 함수 객체는 일반 객체와 다르게 prototype 속성도 가지고있다.

  • [[Prototype]]
    • 함수를 포함한 모든 객체가 가지고 있는 인터널 슬롯.
    • 객체의 입장에서 자신의 부모 역할을 하는 프로토타입 객체를 가리키며 함수 객체의 경우 Function.prototype 을 가리킨다.
    • __proto__ 속성으로 자식객체에서 부모객체의 [[Prototype]]에 접근할 수 있다.
  • prototype 속성
    • 함수 객체만 가지고 있는 프로퍼티이다.
    • 함수 객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 부모 역할을 하는 객체(프로토타입 객체)를 가리킨다.

constructor 속성

프로토타입 객체는 constructor 속성을 가진다. constructor 는 객체 입장에서 자신을 생성한 객체를 가리킨다.

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

let foo = new Person('Carl');

// Person() 생성자 함수에 의해 생성된 객체(prototype)를 생성한 객체는 Person() 생성자 함수이다.
console.log(Person.prototype.constructor === Person);
// output : true

// foo 객체를 생성한 객체는 Person() 생성자 함수이다.
console.log(foo.constructor === Person);
// output : true

// Person() 생성자 함수를 생성한 객체는 Function() 생성자 함수이다.
console.log(Person.constructor === Function);

프로토타입 체인

OOP의 4가지 특징 중 상속을 구현할때 프로토타입 체인을 사용한다.

자식 객체의 경우 부모 객체의 속성이나 메서드를 사용하고 싶을 때 프로토타입을 이용한다.

이 때 원하는 속성이나 메서드가 부모 클래스에서 찾을 수 없는 경우 [[Prototype]] 이 가르키는 링크를 타고 한
단계 더 올라가 검색을 시작한다. 이를 원하는 속성이나 메서드를 찾거나, [[Prototype]] 이 가르키는 링크가 없을때까지 수행한다.

이처럼 부모 - 자식 객체의 프로토타입 객체들이 연결되어있는 모습이 사슬과 같다하여 프로토타입 체인이라고 한다.

const newDiv = document.createElement('div');
newDiv.addEventListener('click', () => console.log('hi'));

newDiv 라는 변수에 div 태그를 저장하였다. 그 후 클릭 이벤트를 addEventListener 메서드를 통해
바인딩했다. 이 addEventListener 메서드는 어디에 존재할까?

[[Prototype]] 에 접근하기 위해 .__proto__ 속성을 사용하였다. 이를 통해 div 태그는 HTMLDivElement 인터페이스의 인스턴스인 것을 알 수 있었다. 하지만
프로토타입 객체에 addEventListener 메서드는 보이지 않는다. 더 상위로 올라가보자.

.__proto__ 속성을 통해 5번이나 링크를 타고 올라간 이후에야 EventTarget 객체의 프로토타입
객체에서 addEventListener 메서드를 발견할 수 있었다.

🎯 참고
PoeimaWeb - 프로토타입

profile
FrontEnd Engineer를 목표로 공부합니다.

0개의 댓글