프로토타입

1Hoit·2023년 1월 13일
0

자바스크립트

목록 보기
8/25

들어가기에 앞서...

자바스크립트는 명령형, 함수형, 프로토타입 기반, 객체지향 프로그래밍을 지원하는 멀티 패러다임 언어다.
--> 프로토타입 기반의 객체지향 프로그래밍 언어이다!
추가적으로 객체지향 프로그래밍에 대해서는 해당 이름의 포스트를 참고하길 바란다.

상속과 프로토타입?

  • 상속은 객체지향 프로그래밍의 핵심 개념으로 어떤 객체의 프로퍼티나 메서드를 다른 객체가 상속받아 사용할 수 있는 것을 말한다.
  • 프로토타입(Prototype)원형 객체이다
  • 자바스크립트는 프로토타입을 기반으로 상속을 구현하여 불필요한 중복을 제거하며 이는 기존의 코드를 재사용 하는 것이다.

프로토타입 (=프로토타입 객체)

  • 프로토타입은 어떤 객체의 상위(부모) 객체의 역할을 하는 객체를 지칭한다.
  • 모든 객체는 [[Prototype]] 이라는 내부 슬롯을 가지며 이 내부 슬롯의 값은 프로토타입의 참조 값이다.
  • 모든 객체는 하나의 프로토타입을 갖는다. 다만 내부 슬롯 [[Prototype]]에 저장되는 프로토타입은 객체 생성방식에 의해 결정될 뿐이다.
  • 모든 프로토타입은 생성자 함수와 연결되어 있다.
    • 객체프로토타입생성자 함수는 서로 연결되있다.
      이 그림을 쉽게 말하자면 [[Prototype]] 내부 슬롯에는 직접 접근할 수 없지만 __proto__ 접근자 프로퍼티로 자신의 [[Prototype]] 내부슬롯이 가리키는 프로토타입에 간접적으로 접근할 수 있다. 그리고 프로토타입은 자신의 constructor 프로퍼티를 통해 생성자 함수에 접근할 수 있고 생성자 함수는 자신의 prototype 프로퍼리를 통해 프로토타입에 접근할 수 있다.

__proto__ 접근자 프로퍼티

  • 모든 객체는 __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입 ([[Prototype]] 내부슬롯)에 간접적으로 접근할 수 있다.
  • __proto__ 접근자 프로퍼티는 상속을 통해 사용된다. 즉 객체가 직접 소유하는 프로퍼티가 아니라 Object.prototype의 프로퍼티다.
    --> 프로토타입의 최상위 객체는 Object.prototype이다.
  • __proto__ 접근자 프로퍼티를 코드 내에서 직접 사용하는 것은 권장되지 않는다. 모든 객체가 __proto__ 를 사용할 수 있는 것은 아니기 때문이다.
    (ex) 직접 상속을 통해 객체를 생성한 경우)
    --> 추가적으로 ES5까지 ECMAScript 사양에 포함되지 않는 비표준이어서 호환성 이슈가 있음.

프로토타입의 참조를 취득하고 싶다면?

  • __proto__ 접근자 프로퍼티는 대신
  • Object.getPrototypeOf 메서드를 사용
  • 프로토타입 교체를 원한다면 Object.setPrototypeOf 메서드를 사용

함수 객체의 prototype 프로퍼티

함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다.

처음에는 위의 말이 이해가 가지 않았다. 하지만 몇번씩 관련 내용을 찾아보니 이해가 갔다.

  • prototype 프로퍼티는 생성자 함수가 생성할 객체(인스턴스)의 프로토타입을 가리킨다.
  • 따라서 non-constructor인 화살표 함수와 ES6 메서드 축약 표현으로 정의한 메서드는 prototype 프로퍼티를 소유하지 않고 프로토타입도 생성하지 않는다.
  • 일반 함수(함수선언문과 표현식)도 prototype 프로퍼티를 소유하지만 객체를 생성하지 않기에 아무런 의미가 없다.

여기서 잠깐!

__proto__ 접근자 프로퍼티와 prototype 프로퍼티 비교

구분소유사용주체사용목적
__proto__ 접근자 프로퍼티모든객체프로토타입 참조모든객체자신의 프로토타입에 접근 또는 교체
prototype 프로퍼티constructor프로토타입 참조생성자 함수생성할 인스턴스의 프로토타입을 할당하기 위해 사용

모든 프로토타입은 constructor 프로퍼티를 갖고 constructor 프로퍼티는 prototype 프로퍼티로 자신을 참조하는 생성자 함수를 가리킨다.

//생성자 함수
function Person(name){
	this.name=name;
}
//me 인스턴스 생성
const me = new Person("Lee");
//1번그림 - 
console.log(Person.prototype === me.__proto__); //true 
//2번그림
console.log(me.constructor=== Person); //true
  • 그림으로 이해해 보자
    1번 그림

    2번 그림

  • 모든 프로토타입은 constructor 프로퍼티를 가짐

  • 이 constructor 프로퍼티는 prototype 프로퍼티로 자신을 참조하고 있는 생성자 함수를 가리킴

  • 즉, me 객체는 프로토타입의 constructor 프로퍼티를 통해 생성자 함수인 Person과 연결되는 것이다.

  • me 객체엔 constructor 프로퍼티 가 없지만 me 객체의 프로토타입인 Person.prototype의 constructor 프로퍼티를 상속받아 사용할 수 있는 것이다.

  • 이를 보면 프로토타입생성자 함수는 언제나 쌍으로 존재한다!


프로토타입 체인

프로토타입 체인은 프로토타입이 단방향 링크드 리스트 형태로 연결되어 있는 상속 구조를 말한다.

객체의 프로퍼티나 메서드에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티 또는 메서드가 없다면 프로토타입 체인을 따라 프로토타입의 프로퍼티나 메서드를 차례대로 검색한다.

  • 예를 들어보자
function Person(name){
	this.name = name;
}

//프로토타입 메서드
Person.prototype.sayHi = function(){
	console.log(`Hi ${this.name}`);
};

const me = new Person("Joe");

// hasOwnProperty 는 Object.prototype 메서드임
console.log(me.hasOwnProperty("name")); // true
console.log(Object.getPrototypeOf(me)===Person.prototype); //true
console.log(Object.getPrototypeOf(Person.prototype) === Object.prototype); //true

  • Person 생성자 함수의 인스턴스 me 객체는 Object.prototype 의 메서드인 hasOwnProperty 메서드 사용이 가능하다
  • 이를 통해 me 객체는 Person.prototye과 Object.prototype 도 상속 받았다는 것을 의미한다.
  • me 객체의 프로토타입은 Person.prototype 이다
  • Person.prototye의 프로토타입은 Object.prototype이다.
    (프로토타입의 프로토타입은 항상 최상위 객체인 Object.prototype 이다)

마무리..

이 내용을 공부하고 이해함으로써 왜 mdn에 나와있는 각각의 메서드들에 prototype이 붙어있는지, 왜 바로 사용할 수 있는지 알게 되었다.
(ex : Array.prototype.reduce() 메서드등..)

물론 완벽하진 않지만 위 내용을 수정해 나가며 더 알아 보아야겠다.

profile
프론트엔드 개발자를 꿈꾸는 원호잇!

0개의 댓글