- Published on
자바스크립트 프로토타입에 대해 알아보기
요즘 사내 스터디를 통해 자바스크립트를 깊게 이해해보려 하고 있습니다. 프로토타입에 대해 알아봅니다.
이 글은 코어 자바스크립트의 6장 프로토타입의 내용을 기반으로 작성했습니다.
프로토타입이란?
“프로토타입(Prototype)“이라는 단어는 그리스어 protos(πρῶτος, “첫 번째”)와 typos(τύπος, “모델” 또는 “형태”)에서 유래했습니다. 즉, “최초의 형태” 또는 “원형”이라는 의미를 가집니다.
소프트웨어 개발 분야에서는 새로운 기능을 빠르게 테스트하기 위해 만들어지는 초안 코드나 개념적 모델을 프로토타입이라 부릅니다.
그럼 자바스크립트에서는 프로토타입을 어떤 의미일까요?
MDN에서는 Object prototypes에서 아래와 같이 설명합니다.
Javascript에서는 객체를 상속하기 위하여 프로토타입이라는 방식을 사용합니다.
객체를 상속하기 위한 방식이라는 뜻이죠.
하지만 상속이라는 단어는 클래스 기반의 언어에 적합합니다. 자바스크립트는 프로토타입 기반 언어입니다. 프로토타입 기반 언어에서는 복제 또는 참조로 상속의 효과를 얻습니다.
프로토타입 개념 이해
constructor, prototype, instance, proto
앞으로 나오는 개념들은 아래 도식을 기반으로 이해하려고 합니다.

const instance = new Constructor()
- 어떤 생성자 함수(여기선 Constructor)를 new 키워드와 함께 호출하면
- Constructor에서 정의된 내용을 바탕으로 새로운 인스턴스(여기선 instance)가 생성됩니다.
- 이때 instance에는 proto라는 프로퍼티가 자동으로 부여되는데
- 이 프로퍼티는 Constructor의 prototype이라는 프로퍼티를 참조합니다.
여기서 prototype 프로퍼티와 proto의 관계가 프로토타입 개념의 핵심입니다.
그러면 이렇게 해볼 수 있겠네요. 생성자 함수 Person을 정의하고 Person.prototype에 getName 메서드를 지정합니다.
function Person(name) {
this._name = name
}
Person.prototype.getName = function () {
return this._name
}
이제 Person의 인스턴스의 proto는 getName 메서드를 호출할 수 있겠네요.
const suzi = new Person('Suzi')
suzi.__proto__.getName() // undefined
호출은 했는데 undefined가 나왔습니다. this에 바인딩된 대상이 잘못 지정됐기 때문입니다. suzi.proto에는 name 프로퍼티가 없으므로 undefined가 나오게 되는겁니다.
아래와 같이 name 프로퍼티에 값을 추가하고 getName 메서드를 호출하면 값이 나오는 것을 볼 수 있습니다.
const suziNew = new Person('Suzi')
suzi.__proto__._name = 'Suzi__proto__'
suzi.__proto__.getName() // 'Suzi__proto__'
여기서 관건은 this입니다. this를 인스턴스로 사용해야 합니다. 방법은 proto없이 인스턴스에서 곧바로 메서드를 사용하는 것입니다.
const iu = new Person('Jieun')
iu.getName() // 'Jieun'
‘이게 왜 되지?’ 모먼트이지만 이는 proto가 생략 가능한 프로퍼티이기 때문입니다. 이 정의를 바탕으로 자바스크립트의 전체 구조가 구성돼었다고 해도 과언이 아닐 정도로 이건 그냥 그런가보다 하고 넘길 수밖에 없습니다. 우리는 proto가 생략 가능하다는 것만 알고 가면 됩니다.

이제 위 그림 정도로 설명이 됩니다.
이 쯤에서 중간 정리를 해보겠습니다.
어떤 생성자 함수를 new 연산자와 함께 호출하면 Constructor에서 정의된 내용을 바탕으로 새로운 인스턴스가 생성되는데, 이 인스턴스에는 proto라는, Constructor의 prototype 프로퍼티를 참조하는 프로퍼티가 자동으로 부여됩니다.
proto는 생략 가능한 프로퍼티라서 인스턴스는 Constructor.prototype의 메서드를 마치 자신의 메서드인 것처럼 호출할 수 있습니다.
constructor 프로퍼티
생성자 함수의 프로퍼티인 prototype 객체 내부에는 constructor라는 프로퍼티가 있습니다. 인스턴스의 proto 객체 내부에도 마찬가지입니다. 이 프로퍼티는 단어 그대로 원래의 생성자 함수(자기 자신)을 참조합니다. 인스턴스의 원형이 무엇인지를 알 수 있는 수단입니다.
constructor 프로퍼티에 접근하는 방법은 여러가지가 있습니다.
function Person(name) {
this.name = name
}
const p1 = new Person('사람1') // true
const p1Proto = Object.getPrototypeOf(p1) // true
const p2 = new Person.prototype.constructor('사람2') // true
const p3 = new p1Proto.constructor('사람3') // true
const p4 = new p1.__proto__.constructor('사람4') // true
const p5 = new p1.constructor('사람5') // true
;[p1, p2, p3, p4, p5].forEach((p) => {
console.log(p, p instanceof Person)
})
마치며
prototype은 자바스크립트의 기반이 되는 개념이기 때문에 깊게 알 필요가 있다고 생각했습니다. 의도치않은 동작이 발생할 때 빠르게 디버깅할 수 있는 주요 개념이라고 생각합니다.
추가로 프로토타입과 관련하여 중요한 개념인 프로토타입 체이닝이라는 개념이 있는데, 다음 글에서 이어서 알아보도록 하겠습니다.