프로토타입
데브 코스/TIL

프로토타입

 자바스크립트는 프로토타입기반 객체지향 언어이다.

클래스 기반 객체지향 언어는 객체 생성 이전에 클래스를 정의하고 이를 통해 객체를 생성한다. 

그런 JS는 클래스 없이도 객체를 생성할 수 있다.(ES6에서 클래스가 추가됨.)

 

자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 객체와 연결되어 있다. 

이것은 객체 지향의 상속 개념과 같이 부모의 객체 프로퍼티 또는 메소드를 상속받아 사용할 수 있게한다.

이러한 부모 객체를 프로토타입 객체 || 프로토 타입 이라고 한다.

 

더보기

자바스크립트의 모든 객체는 [[Prototype]]이라는 인터널 슬롯을 가진다. 이 내부 슬롯 값은 프로토타입의 참조이다.

(인터널 슬롯은 자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 의사 프로퍼티와 의사 메서이다.(pseudo property / pseudo method: 프로그래밍 언어의 문법에 따라 쓴 것이 아니라 일반적 언어로 써 놓은것))

(객체는 프로퍼티의 집합이며, 프로퍼티는 키와 값으로 구성된다)

객체를 생성할 때 프로토타입은 결정되고 [[Prototype]]에 저장된다. 결정된 프로토타입 객체는 다른 임의의 객체로 변경할 수 있다. 이러한 특징을 활용하여 객체의 상속을 구현할 수 있다. (lenght라든가 기타 등등)

 

그래서 어따씀?

function Circle(radius) {
	this.radius = radius;
    this.getArea = function() {
    	return Math.PI * this.radius ** 2;
     };
}

const cir1 = new Circle(1);
const cir2 = new Circle(2);

// 같은 생성자 함수를 사용했지만 서로 갖고있는 메서드가 다르다.
console.log(cir1.getArea === cir2.getArea) /// false;
// 알 수 있는것은 같은 로직을 갖는 메서드를 중복해서 생성한다는 것이다.
// getArea메서드는 하나만 생성하여 모든 인스턴스가 공유해서 사용하는 것이 바람직하겠죠?
function Circle(radius) {
	this.radius = radius;
}

// 이렇게 생성된 프로퍼티는 프로토타입 체인에 즉각 반영됩니다.
Circle.prototype.getArea = function() {
	return Math.PI * this.radius ** 2;
};

// 이제 인스턴스들이 중복된 메서드를 생성하지 않습니다!
const cir1 = new Circle(1);
const cir2 = new Circle(2);

Deep Dive 263p

이처럼 상속은 재사용이란 관점에서 매우 유용하다.

프로퍼티나 메서드를 프로토타입에 미리 구현해 두면 생성자 함수가 생성할 모든 인스턴스는 별도의 구현 없이 프로토타입의 자산을 공유하여 사용할 수 있다.

 

__proto__ 접근자를 사용하여 프로토타입에 접근할 수 있다. 하지만 모든 객체가 __proto__ 접근자 프로퍼티를 사용할 수 있는것은 아니기 때문에 코드 내에서 사용하는것은 권장되지 않는다.

 

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

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

const me = new Person('Lee');

// me 객체의 생성자 함수는 Person 이다.
console.log(me.constructor === Person); // true

me객체에는 constructor 프로퍼티가 없지만 프로토타입에서 상속받아서 사용할 수 있다.

 

그럼 생성자 함수 안쓰고 객체 리터럴로 생성하면 어쩜?

object 생성자 함수에 인수를 전달하지 않거나 undefined 또는 null을 인수로 전달하면서 호출하면 OrdinaryObjectCreate(추상 연산)을 호출하여 Object.prototype을 프로토타입으로 갖는 빈 객체를 생성한다.

그러므로 object생성자 함수 호출이나 객체 리터럴의 평가는 OrdinaryObjectCreate를 호출하여 빈 객체를 생성하는 점에서 동일하나 new.target의 확인이나 프로퍼티를 추가하는 처리 등 세부 내용은 다르다.

 

 결론은 리터럴 표기법에 의해 생성된 객체도 가상적인 생성자 함수를 갖는다.

프로토타입은 생성자 함수와 더불어 생성되며 prototype, constructor 프로퍼티에 의해 연결되어 있기 떄문이다.

프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재한다.

 

리터럴 표기법 생성자 함수 프로토 타입
객체 리터럴 Object Object.prototype
함수 리터럴 Function Function.prototype
배열 리터럴  Array Array.prototype
정규 표현식 리터럴 RegExp RegExp.prototype

 

js는 객체의 프로퍼티에 접근하려 할 때 해당 객체에 접근하려는 프로퍼티가 없다면 [[Prototype]] 내부 슬롯의 참조를 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다. 이를 프로토타입 체인이라 한다.

 프로토타입 체인의 종점에도 프로퍼티를 검색할 수 없는 경우 undefined를 반환한다. 이때 에러가 발생하지 않는다.

 

 

 

[[Prototype]] vs prototype 프로퍼티

 

[[Prototype]] 

함수를 포함한 모든 객체(원시타입 제외 모든것)가 갖고 있는 인터널 슬롯이다.

함수 객체의 경우 Funtion.prototype을 가리킨다. (함수를 생성하는 3가지 방식모두 결국 Function() 생성자 함수를 통해 함수 객체를 생서하기 때문이다)

함수의 경우 함수 생성자 함수를 사용하기 때문에 '생성자 함수이름.prototype'을 바라본다.

prototype 프로퍼티

함수 객체만 가지고 있는 프로퍼티이다.

 

 

 

 

 

 

'데브 코스 > TIL' 카테고리의 다른 글

화살표 함수  (0) 2022.12.20
[React]setInterval  (0) 2022.12.20
[회고]노션 클로닝.  (0) 2022.11.25
[TIL]선언형 프로그래밍.  (0) 2022.10.28
[TIL]Day9  (0) 2022.10.27