자바스크립트는 프로토타입 기반의 언어입니다. 현재 ES6문법에 class를 사용할 수 있지만 class역시 프로토타입을 기반으로 구성된 것이기 때문에 프로토타입을 이해하면 클래스를 포함한 자바스크립트를 다루는데 능숙해질 것이라고 생각됩니다.
근데 이것만으로는 프로토타입,클래스를 왜 써야되는지 이해가 안가시지 않나요?
여기에 결정적인 이유가 있습니다.
function Person(name){
this.name=name
this.sayHello=()=>{
console.log(this.name)
}
}
const kyle = new Person('kyle')
kyle : Person {name: "kyle", sayHello: ƒ}
이렇게 작성했을 때 kyle의 객체안에는 name프로퍼티와 sayHello메소드가 둘다 들어있습니다.
이렇게 생성자함수를 이용해서 생성을 한다면 프로퍼티와 메소드를 그대로 갖고와버리기 때문에 메모리 할당에 부담이 됩니다.
이것을 sayHello()
를 프로토타입 메소드로 할당을 해보겠습니다.
function Person(name){
this.name=name
}
Person.prototype.sayHello=function(){
console.log(this.name)
}
const kyle = new Person('kyle')
위 그림과 같이 kyle객체에 메소드가 들어있는게 아니라 prototype객체로 부터 상속을 받아서 사용할 수 있습니다.
직접적으로 객체에 넣어주는것이 아닌 참조를 통해서 사용하기 때문에 메모리가 절약됩니다!
class도 이와 같이 작동하게 됩니다.
이제 프로토타입에 대해 자세히 알아보고 싶은 마음이 생기셨나요??
프로토타입이란 사전적 의미로 원래의 형태입니다.
자바스크립트의 모든 객체는 자신을 생성한 객체 원형에 대한 연결을 갖고있습니다. 이때 자신을 생성하기 위해 사용된 객체원형을 프로토타입이라 합니다.
위와 같이 자신을 생성한 객체와 연결이 되있기 때문에 상속과 같이 부모객체의 프로퍼티 또는 메소드를 사용할 수 있게 되는 것이다.
모든 객체는 proto로 접근할 수 있는 prototype객체를 가지며 이것을 prototype이라고도 부른다.
둘의 차이는 간단합니다.
prototype 프로퍼티는 함수에만 있다.
prototype객체는 자바스크립트의 모든 객체에 다있습니다.
위의 사용했던 코드를 가져와서 크롬에서 내부를 살펴보겠습니다.
function Person(name){
this.name=name
}
Person.prototype.sayHello=function(){
console.log(this.name)
}
const kyle = new Person('kyle')
위 그림과 같이 Person 함수에는 prototype프로퍼티가 있습니다.
반면에 인스턴스인 kyle에는 없죠!
그럼 생성자함수에 prototype프로퍼티는 어디에 사용될까요?? 제가 표시한 것을 보시면 눈치를 채셨을 것입니다.
네! 맞습니다. 생성자함수의 prototype프로퍼티는 인스턴스의 프로토타입 객체 (proto가 가르키는 객체)가 됩니다!
즉, 인스턴스의 prototype객체 === 생성자 함수의 prototype 프로퍼티
그럼 위의 사진에서 인스턴스 프로토타입 객체의 constructor와 생성자 함수의 constructor는 무엇일까요??
constructor는 말 그대로 생성자입니다. 현재의 객체를 누가 만들어 주었는지 써있는 것입니다.
그럼 예상을 해보겠습니다.
Person()
Function()
Person 함수의 prototype 프로퍼티는 === kyle 인스턴스의 프로토타입 객체이다.
kyle 인스턴스의 프로토타입 객체에는 kyle 인스턴스의 constructor가 작성돼 있다. kyle 인스턴스의 constructor===Person()
이다. 그렇기 때문에 Person 함수의 prototype 프로퍼티 === Person()
최종정리
- 인스턴스의 constructor : 생성자함수
- 생성자 함수의 constructor : Function()
- 생성자 함수의 prototype 프로퍼티의 construcor : 생성자함수
(위 두 생성자 함수는 같은 생성자 함수이다.)
위의 코드에서 프로토체인 현상을 발견할 수 있습니다.
kyle 인스턴스에서 sayHello()
메소드를 활용하기 위해서는 자신의 객체를 찾아보고 없다면 -> 프로토타입 객체를 탐색해서 sayHello()
메소드를 실행하게 됩니다.
이렇게 자신이 필요한 프로퍼티 또는 메소드를 프로토타입 객체로 찾아가는 검색해보는 현상을 프로토타입 체인이라고 합니다.
이제 다시 위의 예제를 보겠습니다.
Person 생성자 함수의 프로토타입객체는Function.prototype
입니다.
Function()의 프로토타입 객체는 Ojbect.prototype
입니다.
(프로토타입 객체 === 생성자의 prototype프로퍼티이기 때문입니다.)
이렇게 프로토타입 객체가 이어져 있기 때문에 Person생성자 함수, kyle인스턴스 등이 Object의 메소드를 사용할 수 있는 것입니다.
ex)kyle.hasOwnProperty(name) //true
모든 자바스크립트는 프로토타입 객체의 끝에 Object.prototype가 있기 때문에 객체메소드를 사용할 수 있다.
여기서 한가지 질문이 생깁니다.
let str = 'hello'
같은 원시타입(string, number, boolean, null, undefined)는 객체가 아니기 때문에 프로퍼티 혹은 메소드를 가질 수 없습니다.
어떻게 사용 가능할까?
원시타입으로 프로퍼티 혹은 메소드를 호출할 때 원시 타입과 연관된 객체로 일시적으로 변환되어 프로토타입 객체를 공유하게 된다.
단, 객체가 아니기 때문에 프로퍼티 혹은 메소드를 추가할 수 없다.
프로토타입에 대해 간단하게 알아봤습니다. 이 글은 poiemaweb-prototype을 참고해서 작성한 글입니다.
프로토타입을 처음 겪었을 때 용어가 비슷해 헷갈리는 경우가 많았는데 이렇게 한번 정리를 하면서 용어들과 개념이 정리가 된 것 같습니다.