[코어 자바스크립트] 6장 프로토타입

woo·2023년 4월 18일
0
post-thumbnail

6-1 프로토타입의 개념 이해

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

6-1-1 constructor, prototype, instance

const instance = new Constructor();

  • 어떤 생성자 함수(Constructor)를 new 연산자와 함께 호출하면
  • Constructor에서 정의된 내용을 바탕으로 새로운 instance가 생성된다.
  • 이때 instance에는 __proto__라는 프로퍼티가 자동으로 부여되는데
  • 이 프로퍼티는 Constructor의 prototype이라는 프로퍼티를 참조한다.
  • prototype가 객체이기에 __proto__또한 객체이다.

prototype 객체 내부에는 instance가 사용할 메서드가 저장되어있는데 인스턴스의 숨겨진 프로퍼티인 __proto__를 통해 이 메서드에 접근할 수 있다.
(__proto__를 통해 메서드에 접근하는 것보다 Object.getPrototypeOf() / Object.create()를 이용해 접근하는 것이 범용성이 높다.)

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

Person.prototype.getName = function() { //getName 메서드
   return this._name;
};

const suzi = new Person('Suzi');
suzi.__proto__.getName();  // undefined

어떤 함수를 '메서드로서' 호출할 때는 메서드명 바로 앞의 객체가 곧 this가 된다. 따라서 suzi.__proto__.getName() 에서 getName 함수 내부에서의 this는 suzi가 아니라 suzi.__proto__라는 객체가 되는 것이다. 이 객체 내부에는 name 프로퍼티가 없으므로 undefined를 반환한 것이다.

__proto__ 객체에 name 프로퍼티가 있도록 하면 정상적으로 원하는 값이 출력된다.

const suzi = new Person('Suzi');
suzi.__proto__._name = "SUZI__proto__"; 
suzi.__proto__.getName();  // SUZI__proto__

__proto__ 없이 instance에서 바로 메서드를 쓰면 this가 가리키는 것을 instance로 만들 수 있다. __proto__가 생략 가능한 프로퍼티이기 때문이다.

suzi.__proto__.getName(); 
-> suzi(.__proto__).getName();
-> suzi.getName(); // Suzi

따라서 다음과 같은 도식이 성립된다.

예를 들어 array에서 isArray() 메서드는 프로퍼티 내부에 있지 않아 인스턴스가 직접 호출할 수 없고 Array 생성자 함수에서 직접 접근해서 실행해야한다.
반면 push() 메서드는 프로프티 내부에 있어 인스턴스가 직접 호출 가능하다.

const arr = [1, 2];
Array.isArray(arr); // (O)
arr.isArry();       // (X) TypeError

arr.push(3) // (O)

6-1-2 constructor 프로퍼티

생성자 함수의 프로퍼티인 prototype 객체 내부에는 constructor라는 프로퍼티가 있다. prototype에 있으니까 prototype를 참조하는 instance의 __proto__객체 내부에도 있다.
constructor 프로퍼티는 생성자 함수(자기 자신)을 참조하여 인스턴스로부터 그 원형이 무엇인지를 알 수 있는 수단이 된다.

한편 constructor는 읽기 전용 속성이 부여된 예외적인 경우(✱기본형 리터럴 변수 - number, string, boolean)을 제외하고는 값을 바꿀 수 있다. 하지만 constructor를 변경하더라도 참조 대상이 변경될 뿐 이미 만들어진 인스턴스의 원형이 바뀐다거나 데이터 타입이 변하는 것은 아니다. 따라서 어떤 인스턴스의 생성자 정보를 알아내기 위해 constructor 프로퍼티에 의존하는 것이 안전하지는 않다.

6-2 프로토타입 체인

6-2-1 메서드 오버라이드

동일한 이름의 프로퍼티 또는 메서드를 가지고 있으면 자신으로부터 가장 가까운 메서드부터 접근한다.
this가 instance의 __proro__에 접근하려면 call, apply를 사용하면된다.

6-2-2 프로토타입 체인

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

데이터 타입별 프로토타입 체인은 다음과 같다.

6-2-3 객체 전용 메서드의 예외 사항

Object.prototype은 언제나 프로토타입 체인의 최상단에 존재한다.
다만 예외적으로 Object.create(null)로 __proro__ 가 없는 객체를 생성하면 Object.prototype에 접근할 수 없는 경우가 있다.

6-2-4 다중 프로토타입 체인

사용자가 대각선의 __proro__ 을 연결하면 무한대로 체인 관계를 이어나갈 수 있다.
대각선의 __proro__ 를 연결하려면 __proro__ 가 가리키는 대상, 즉 생성자함우의 prototype이 연결하고자 하는 상위 생성자의 instance를 바라보도록 해주면 된다.

profile
🌱 매일 성장하는 개발자

0개의 댓글

관련 채용 정보