프로토타입 | 코어자바스크립트 6

dana·2022년 3월 28일
3

Javascript / algorithm

목록 보기
13/15
post-thumbnail

자바스크립트는 프로토타입 기반 언어
클래스 기반 언어에서는 상속을 사용하지만
프로토타입 기반 언어에서는 어떤 객체를 원형으로 삼고 이를 복제(참조)함으로써 상속과 비슷한 효과를 냄.

프로토타입의 개념 이해

constructor, prototype, instance

  1. 어떤 생성자 함수(constructor)를 new 연산자와 함께 호출하면
  2. constructor에서 정의된 내용을 바탕으로 새로운 인스턴스가 생성
  3. 이때 instance에서는 __proto__라는 프로퍼티가 자동으로 부여
  4. 이 프로퍼티는 constructor의 prototype이라는 프로퍼티를 참조

prototype와 __proto__는 객체
prototype 객체 내부에는 인스턴스가 사용할 메서드를 저장
인스턴스에서도 숨겨진 프로퍼티인 __proto__를 통해 이 메서드에 접근 가능
하지만 실무에서는 직접 던더프로토에 접근하는것이 권장되지 않음.
Object.getPrototypeOf() / Object.create() 등을 대신 이용

만약 person이라는 생성자 함수의 prototype에 getName이라는 메서드를 지정시

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

Person.prototype.getName = function() {
  return this._name;
}

Person의 인스턴스는 __proto__ 프로퍼티를 통해 getName을 호출 가능
만약 여기서 새로운 인스턴스를 생성한다면,

let apple = new Person('Suzi');
apple.__proto__.getName(); //undefined

apple의 던더프로토가 참조하는 name은 Person의 name이기 때문에, 현재 아무 값도 할당되어있지 않아 undefined가 출력됨.
따라서 다음과 같은 공식이 성립한다는 것을 알 수 있음

Person.prototype === apple.__proto__ // true

인스턴스의 던더프로토는 생략 가능하기 때문에 다음과 같은 공식도 성립

Person.prototype === apple // true

따라서 정리해본다면, new 연산자로 Constructor를 호출하면 instance가 만들어지는데, 이 instance의 생략 가능한 프로퍼티인 __proto__는 Constructor의 prototype을 참조함.
생성자 함수의 prototype에 어떤 메서드나 프로퍼티가 있다면, 인스턴스에서도 마치 자신의 것처럼 해당 메서드나 프로퍼티에 접근할 수 있게됨.

contructor 프로퍼티

원래의 생성자함수(자기 자신)을 참조하는 프로퍼티
인스턴스로부터 그 원형이 무엇인지 알 수 있는 수단

인스턴스에서 contructor에 직접적인 접근이 가능

constructor는 읽기 속성이 부여된 예외적인 경우를 제외하고 값 변경 가능
(읽기 속성이 부여된 예외적인 경우 : 기본형 리터럴 변수 - number, string, boolean)
참조하는 대상이 변경될 뿐 이미 만들어진 인스턴스의 원형이 바뀐다거나 데이터 타입이 변하는 것은 아님.

= 어떤 인스턴스의 생성자 정보를 알아내기 위해 constructor 프로퍼티에 의존하는 것이 항상 안전하진 않음.

다양한 constructor 접근 방법

모두 동일한 Constructor를 가리키는 코드

[Constructor]
[instance].__proto__.constructor
[instance].constructor
Object.getPrototypeOf([instance]).constructor
[Constructor].prototype.constructor

모두 동일한 객체를 가리키는 코드

[Constructor].prototype
[instance].__proto__
[instance]
Object.getPrototypeOf([instance])

프로토타입 체인

메서드 오버라이드

만약 인스턴스가 동일한 이름의 프로퍼티 또는 메서드를 가지고 있다면?

자바스크립트 엔진이 getName이라는 메서드를 찾는 방식은 가장 가까운 대상인 자신의 프로퍼티를 검색 후, 없으면 그 다음으로 가까운 대상인 __proto__를 검색하는 순서로 진행하기 때문에 인스턴스의 메서드 우선 실행

만약 메서드 오버라이딩이 이뤄진 상태에서 원본의 메서드에 접근하고 싶다면

apple.__proto__.getName() //원본의 getName 출력

프로토타입 체인

모든 객체의 __proto__에는 Object.prototype이 연결

프로토타입 체인 : 어떤 데이터의 __proto__ 프로퍼티 내부에 다시 __proto__ 프로퍼티가 연쇄적으로 이어진 것
프로토타입 체이닝 : 이 체인을 따라가며 검색하는 것

메서드 오버라이딩과 동일한 동작방식으로, 어떤 메서드 호출 시 자바스크립트 엔진은 데이터 자신의 프로퍼티들을 검색해 찾던 메서드가 있으면 그 메서드를 실행하고 없으면 __proto__를 검색해 실행하는 방식

객체 전용 메서드의 예외 사항

  • 어떤 생성자 함수든 prototype은 반드시 객체
  • Object.prototype이 언제나 프로토타입 체인의 최상단에 존재
  • 객체에서만 사용할 메서드는 프로토타입 객체 안에 정의할 수 없음.
    - 객체만을 대상으로 동작하는 객체 전용 메서드들은 부득이 Object.prototype이 아닌 Object에 스태틱 메서드(static method)로 부여

생성자 함수인 Object와 인스턴스인 객체 리터럴 사이에는 this를 통한 연결이 불가능해 대상 인스턴스를 인자로 직접 주입해야 함.

다중 프로토타입 체인

대각선의 __proto__를 연결해나가기만 하면 무한대로 체인 연결 가능

대각선의 __proto__를 연결하는 방법

__proto__가 가리키는 대상, 즉 생성자 함수의 prototype이 연결하고자 하는 상위 생성자 함수의 인스턴스를 바라보도록

profile
PRE-FE에서 PRO-FE로🚀🪐!

4개의 댓글

comment-user-thumbnail
2022년 3월 28일

좋네요 ,,,

1개의 답글
comment-user-thumbnail
2022년 3월 31일

이 글을 읽고 프로토타입에 대한 눈이 뜨였습니다.

1개의 답글