---
# System prepended metadata

title: 프로토 타입

---

# 프로토 타입

## 프로토타입이란?

- 프로토타입이란 디자인 패턴 중 하나로서 객체를 생성할 때 원본이 되는 객체를 복사해서 생성하는 패턴
- 프로토타입 패턴은 객체를 효율적으로 생성하는 방법을 다루는 패턴 중 하나이고 주로 객체를 생성하는 비용이 클 때 이를 회피하기 위해 사용됨
- 자바스크립트는 ES6 부터 class 키워드를 사용하여 클래스를 지원하고 있지만 정확히 말하면 프로토타입으로 클래스를 흉내내서 구현한 것임

## 자바스크립트에서 프로토타입(\_\_proto\_\_, constructor)

- 클래스 기반 언어에서는 클래스를 생성하고 그 클래스를 사용하여 객체를 생성함. 하지만 자바스크립트는 클래스라는 개념 자체가 없으며 함수(Function)을 사용해서 객체를 생성함
- 자바스크립트는 객체를 생성할 때 프로토타입 패턴을 사용하고 함수의 프로토타입 객체를 복제하여 객체를 생성함
- 자바스크립트는 함수가 생성될 때 자동으로 그 함수의 프로토타입 객체(Prototype Object)를 함께 생성하고 해당 함수의 prototype 프로퍼티에 연결한다.

![image](https://gist.githubusercontent.com/ji3427/308e58e69c5f5385af26efe704813d6d/raw/1469bceee17e60893b8f93b2f92e788b329aae48/SS%25EC%2584%25A0%25ED%2583%259D%2520%25EC%2598%2581%25EC%2597%25AD_154.png)

### constructor

함수가 생성되며 함께 생성된 프로토타입 객체는 모두 constructor라는 프로퍼티를 가지고 있다. 그리고 이 프로퍼티에는 이 프로토타입 객체가 생성될 때 선언했던 함수가 들어있다.

![image](https://gist.githubusercontent.com/ji3427/308e58e69c5f5385af26efe704813d6d/raw/1469bceee17e60893b8f93b2f92e788b329aae48/SS%25EC%2584%25A0%25ED%2583%259D%2520%25EC%2598%2581%25EC%2597%25AD_155.png)

#### constructor 프로퍼티의 존재 이유

이 생성자 프로퍼티는 이 함수를 통해 생성된 객체 입장에서 보았을 때 나를 만들 때 어떤 함수가 호출되었냐?를 의미

프로토타입 객체의 constuctor 프로퍼티에 생성자 함수가 연결되어있기 때문에 새롭게 생성된 객체는 자신의 프로토타입 객체에 접근해 이 프로퍼티를 참조함으로써 자신이 만들어질 때 어떤 생성자 함수가 호출되었는지를 알 수 있다.(instanceof 연산자를 통해서 확인할 수 있다.)

### \_\_proto\_\_

> __proto__는 ECMAScript 2015에서는 표준이었지만 현재는 표준이 아니므로 Object.getPrototypeOf(object), Object.setPrototypeOf(object, prototype)를 사용하는 것을 추천

함수의 프로토타입 객체를 복제하여 생성된 객체가 자신의 원본(프로토타입) 객체에 접근할 수 있는 프로퍼티가 바로 \_\_proto\_\_ 이다.

새롭게 생성된 객체와 프로토타입 객체와의 연결을 **프로토타입 링크(Prototype Link)** 라고 한다.

## 프로토타입 체인

프로토타입 링크로 이루어진 객체들의 관계를 프로토타입 체인(Prototype Chain)이라고 한다.

자바스크립트 내에 존재하는 모든 것들은 Object 함수의 프로토타입인 Object.prototype을 시작으로 해서 복제된다. 그렇기 때문에 
Object.prototype 객체는 프로토타입 링크, 즉 프로토타입 객체로 통하는 링크가 없다. 

자바스크립트의 모든 함수는 원본으로 Function.prototype 객체를 가진다. 그리고 Function.prototype은 결국 객체이기 때문에, 당연히 원본으로 Object.prototype 객체를 가진다.

![image](https://gist.githubusercontent.com/ji3427/308e58e69c5f5385af26efe704813d6d/raw/288d1e5871cb692263cabce53d7d85cbb9fb0f8c/%25EC%2584%25A0%25ED%2583%259D%2520%25EC%2598%2581%25EC%2597%25AD_156.png)

### 프로토타입 룩업

프로토타입 체인을 통해 객체의 메서드나 프로퍼티를 찾아가는 과정을 프로토타입 룩업이라고 한다.

```javascript=
var a = {
    attr1: 'a'
};

var b = {
    __proto__: a,
    attr2: 'b'
};

var c = {
    __proto__: b,
    attr3: 'c'
};
// 위의 코드에서는 객체를 세 개 만들고
// 각 객체의 __proto__ 속성을 이용해 c -> b-> a 로 연결했다.

c.attr1 // 'a'
```

현재 객체에서 원하는 프로퍼티를 찾지못하는 경우 객체의 \_\_proto\_\_ 프로퍼티가 참조하는 객체에서 값을 찾는다. 최종적으로 \_\_proto\_\_가 없는 Object 객체까지 올라가고 못 찾은 경우 undefined를 출력한다.

## 프로토타입을 활용한 상속

자바스크립트에서는 `Object.create` 메소드를 사용하여 상속을 구현한다.

### Object.create()

```javascript
Object.create(proto, [propertiesObject])
```

#### 정의

지정된 프로토타입 객체 및 속성(property)을 갖는 빈 객체를 만든다.
여기서 __proto__는 인자로 받은 proto 객체를 가리킨다.
이때 프로퍼티 설명자를 추가로 넘길 수 있다.

### 상속 예제

```javascript=
function SuperClass (name) {
  this.name = name;
}

SuperClass.prototype.say = function () {
  console.log(`I am ${this.name}`);
}

function SubClass (name) {
  SuperClass.call(this, name);
}

SubClass.prototype = Object.create(SuperClass.prototype);
SubClass.prototype.constructor = SubClass;
SubClass.prototype.run = function () {
  console.log(`${this.name} is running`);
}

const subObj = new SubClass('john');
```

#### 1.

![image](https://gist.githubusercontent.com/ji3427/308e58e69c5f5385af26efe704813d6d/raw/c910c363b93f9432f35310c55abd87830b35ba81/Slide112.jpg)

```javascript

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

SuperClass.prototype.say = function () {
  console.log(`I am ${this.name}`);
}

```
SuperClass 함수와 prototype 객체가 만들어지고 prototype의 say 함수를 초기화해주는 코드이다.

#### 2.

![image](https://gist.githubusercontent.com/ji3427/308e58e69c5f5385af26efe704813d6d/raw/24020adf1a111e1ec7667ccd3da4bb9ad3e60280/Slide113.jpg)

```javascript
function SubClass (name) {
  SuperClass.call(this, name);
}
```

SubClass 함수와 prototype 객체가 만들어진 코드이다. 아직까지 SubClass 와 SuperClass와의 연결점은 없다.

※ SubClass에서 call 함수를 호출하는 이유
- 부모클래스의 멤버 변수, 함수들을 자식 클래스에서 초기화하기 위해서이다. JAVA의 super()와 유사한 역할이다.

#### 3.

![image](https://gist.githubusercontent.com/ji3427/308e58e69c5f5385af26efe704813d6d/raw/0055deac52ba11ef0733fa6a78fa59c61a93f50a/Slide114.jpg)

```javascript
SubClass.prototype = Object.create(SuperClass.prototype);
```

SubClass의 prototype를 `Object.create`를 통해 복제된 SuperClass의 prototype으로 변경한다. 이 과정에서 복제된 prototype의 \_\_proto\_\_ 프로퍼티는 SuperClass의 prototype을 가리키게 된다.

#### 4.

![image](https://gist.githubusercontent.com/ji3427/308e58e69c5f5385af26efe704813d6d/raw/0055deac52ba11ef0733fa6a78fa59c61a93f50a/Slide115.jpg)

```javascript
SubClass.prototype.constructor = SubClass;
```

`Object.create()`을 사용할 경우, 새로 만들어진 객체에는 constructor가 존재하지 않는다. 따라서 SubClass prototype 객체의 constructor를 SubClass 함수로 변경한다. 

#### 5.

![image](https://gist.githubusercontent.com/ji3427/308e58e69c5f5385af26efe704813d6d/raw/0055deac52ba11ef0733fa6a78fa59c61a93f50a/Slide116.jpg)

```javascript
SubClass.prototype.run = function () {
  console.log(`${this.name} is running`);
}
```

상속된 SubClass는 \_\_proto\_\_ 프로퍼티를 통해서 부모와 연결되어 있다.
자식 객체에서 변수, 함수를 추가해도 부모에는 영향을 미치지 않는다.

#### 6.

![image](https://gist.githubusercontent.com/ji3427/308e58e69c5f5385af26efe704813d6d/raw/c6cf30e8324d64b55329dc2f1b199d3bcc17486b/image_2021_01_22T08_24_52_169Z.png)

```javascript
const subObj = new SubClass('john');
```

subObj -> SubClass.prototype -> SuperClass.prototype으로 이어지는 프로토타입 체인이 완성된 것을 확인할 수 있다. 이때 subObj 객체의 run이나 say 메소드를 호출하면 위에서 언급한 프로토타입 룩업을 통해 프로토타입 객체의 메소드를 호출할 수 있다.
