자바스크립트는 프로토타입 기반 언어이며 프로토타입이란 원형(유전자)라는 뜻이다. 모든 객체들은 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가진다. 정확히 말하자면 상속되는 속성과 메소드들은 각 객체가 아니라 객체의 생성자의 prototype이라는 속성에 정의되어 있다.
프로토타입은 모든객체에 존재하지 않는다. 자바스크립트는 원시 타입인 boolean, number, string, null, undefined 를 제외한 거의 모든것이 객체이며 함수 또한 객체이다. 함수 객체는 프로토타입이라는 특수한 형태의 객체 프로퍼티를 통해 상속을 하며 함수 객체만이 prototype
프로퍼티를 가진다.
자바의 경우 class 의 개념을 통해 인스턴스를 생성하며 상속을 받는다. 하지만 자바스크립트의 경우 프로토타입 객체를 통해서 상속을 받는다.
코드를 통해 이해해보자.
const Person = function (age, name) { // 생성자 함수
this.age = age;
this.name = name;
}
const sejin = new Person(29, 'sejin') // 새로운 객체
new
키워드는 생성자 함수를 사용하여 객체를 만들 때 쓰는 키워드이다. Person 생성자 함수와 new 키워드를 통해 만들어진 새로운 객체 sejin 은 생성자 함수 Person 의 prototype
프로퍼티를 프로토타입 객체로 상속받는다.
const kanglim = Object.create(sejin)
create() 메소드는 주어진 객체를 프로토타입 객체로 삼아 새로운 객체를 생성한다. 위 코드에서 kanglim 은 sejin 을 프로토타입 객체로 상속받는다.
각 객체가 상속받은 프로토타입 객체는 [[prototype]] 이름으로 은닉되어 있으며 콘솔을 통해서 아래와 같이 확인할 수 있다.
[[prototype]]
에 접근하기 위해서는 아래와 같이 코드를 입력하면 된다.
sejin.__proto__
// 또는
Object.getPrototypeOf(sejin)
결론적으로 위의 코드에서 kanglim 에게 상속을 내려주는 프로토타입 객체는 sejin 이며
sejin 에게 상속을 내려주는 프로타입 객체는 생성자 함수 Person 의 prototype
프로퍼티 이다.
자바 스크립트에서 모든 객체는 객체를 통해서 생성이 된다. 그렇다면 Person 의 prototype
프로퍼티에게 상속을 내려주는 프로타입 객체는 무엇일까.
바로 Object 함수이다. 자바스크립에서 생성자 함수의 prototype
프로퍼티는 Object 함수의 prototype
프로퍼티로 부터 상속을 받아 만들어진다.
따라서 아래 코드는 모두 참이 된다.
console.log(kanglim.__proto__ === sejin); // true
console.log(sejin.__proto__ === Person.prototype) // true
console.log(Person.prototype.__proto__ === Object.prototype) // true
추가로 우리가 리터럴 하게 사용하는 아래의 코드는 모두 내부적으로 new 키워드와 자바스크립트에서 제공하는 생성자 함수를 통해 만들어 진다.
const obj = {} // const obj = new Object(); 와 같음
const arr = [] // const arr = new Array(); 와 같음
프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지이다. 이를 프로토타입 체인(prototype chain)이라 부르며 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 하는 근간이 된다.
때문에 위의 코드에서 sejin 과 kanglim 객체는 모두 Object 의 프로토타입 객체에 있는 메소드 valueOf(), toString() 등을 사용할 수 있다. 하지만 keys, is 의 경우는 Object 프로토타입 객체에 해당하지 않으며 Object 객체 자체에 있기 때문에 Object 객체를 통해서만 사용할 수 있다.
프로토타입 체인에서 한 객체의 메소드와 속성들이 다른 객체로 복사되는 것이 아님을 재차 언급합니다. — 위에서 보시다 시피 체인을 타고 올라가며 접근할 뿐입니다.
const Person = function (age, name) { // 생성자 함수
this.age = age;
this.name = name;
}
const sejin = new Person(29, 'sejin') // 새로운 객체
Person.prototype.introduce = function () {
console.log(this.age);
console.log(`안녕하세요!! 저는 ${this.age}살 입니다.`)
};
sejin.introduce();
생성자 함수의 프로토타입을 수정하면 생성자 함수의 프로토 타입 객체로 부터 생성된 객체(인스턴스)들은 모두 추가된 메소드를 사용할 수 있다.