prototype이란?

Java, C++과 같은 클래스 기반 언어와 달리 자바스크립트는 프로토타입 기반 프로그래밍 언어라고 불린다. 그러면 프로토타입이란 무엇일까?
JavaScript는 클래스 개념이 없다. 그래서 다른 객체의 속성을 상속하는게 불가능했다. 하지만 이를 가능하게 만들어준 것이 바로 prototype이다. 객체의 원형인 프로토타입을 이용하여 새로운 객체를 생성해 내면, 새로 생성된 객체는 기존 객체의 프로토타입 속성을 상속받는 것이 가능해진다.
(ES6에서는 class가 추가되었다.)
프로토타입은 다음과 같이 console.dir()을 이용하여 확인해 볼 수 있다.

var student = {
    name: 'Steve',
    score: 80
}

console.dir(student);

위의 __proto__ 부분이 student객체의 프로토타입이다.

__proto__

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

var person1 = new Person('raonzena');
console.dir(Person);
console.dir(person1);

생성자 함수를 만든 후 객체에 할당해보자.
위 소스는 Person이라는 생성자 함수를 만든 후 person1이라는 객체에 할당한 것이다.
console.dir로 객체 내부 구조를 확인해 보면 다음과 같이 Person의 prototype이 person1의 __proto__에 상속이 된 것을 알 수 있다.

먼저 Person객체를 보면, function 속성이라는 것을 알 수 있다.
그리고 prototype 프로퍼티 내부에 constructor와 __proto__라는 두 가지 프로퍼티가 존재한다. 그리고 __proto__ 라는 프로퍼티가 있다.
prototype 프로퍼티 내부의 constructor는 function Person(name)이라고 되어있고, __proto__는 object라고 되어있다.
모든 객체는 Object를 최상위 부모객체로 가진다.여기서 __proto__ 속성은 부모객체를 가리킨다는 것을 알 수 있다. 따라서 Person의 부모 객체는 Object이다. 또한, Person을 상속받은 person1 객체도 Object를 부모 객체로 상속 받았다는 것을 알 수 있다.

constructor

그러면 constructor 속성은 무엇을 나타내는 것일까? 위에서 prototype 프로퍼티 안에 constructor라는 속성이 하나 더 있다는 것을 알아내었다.
그리고 Person의 constructor는 function Person(name)이라는 것이다.
자바스크립트에서는 함수를 생성할 때 함수 자신과 연결된 프로토타입 객체를 동시에 생성하며, 서로 prototype과 constructor로 연결된다.
함수(prototype) <—> 프로토타입객체(constructor)

위의 person1객체를 보면 person1객체는 Person객체가 할당되므로 name속성만 “raonzena”로 바뀌고 객체의 구조는 Person이라는 것을 알 수 있다. __proto__ 속성을 확인해 보면 Person객체의 prototype 속성과 일치한다. 따라서 person1객체는 Person객체의 속성을 모두 사용할 수 있다.
즉, 생성자 함수로 할당된 객체는 내부의 __proto__ 속성이 해당 생성자 함수의 prototype 속성을 가리키므로 생성자 함수내의 모든 속성과 메소드 등을 사용할 수 있는 것이다.

정리하면, 함수(Person)를 만들면 그 함수는 자신의 프로토타입 객체(Person.prototype)를 만들고 함수내의 prototype과 프로토타입 객체내의 constructor와 연결된다. 함수를 참조하는 객체(person1)는 함수의 프로토타입 객체와 __proto__ 이라는 자신의 내부 프로퍼티와 연결이 되어 해당 함수(Person)의 속성과 메소드에 접근이 가능하다.

prototype chain

위의 내용에 따르면 객체는 자신의 __proto__ 프로퍼티를 통해서 상위객체의 접근이 가능하다는 것이다.
이것을 ‘프로토타입 체인’이라고 한다. 특정 객체의 프로퍼티나 메소드에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티나 메소드가 없다면, __proto__를 따라 자신의 부모 객체의 프로토타입 프로퍼티나 메소드를 차례로 검색한다.

var student = {
    name: 'raonzena',
    score: 90
}

console.log(student.hasOwnProperty('name')); // true

위 소스에서 student라는 객체는 hasOwnProperty라는 메소드를 가지고 있지 않은데도 에러가 발생하지 않고 true를 리턴한다.
이는 student객체의 __proto__를 따라가서 student의 부모인 프로토타입 객체(Object.prototype)의 hasOwnProperty 메소드를 찾아 호출하였기 때문이다.