-
프로토타입(Prototype)frontend/javascript&web 2022. 2. 16. 08:49
Concept By 프로토타입 (Concept By Prototype)
프로토타입
- 자바스크립트는 프로토타입 기반의 언어, 객체 원형인 프로토타입을 이용하여 새로운 객체를 생성
자바스크립트는 프로토타입이라는 특수한 객체를 가지고 있으며, 이는 말그대로 다른 객체의 원형이 되는 객체 입니다. 새로운 객체를 만들어 낼 때 객체의 원형인 프로토 타입을 이용하며, 이를 통해 객체를 확장하고 객체 지향적인 프로그래밍을 할 수 있도록 도와줍니다.
예시
let fn = { // (1) getName() { return this.name }, getAge() { return this.age } }; function Person(name){ // (2) let newPerson = {}; Object.setPrototypeOf(newPerson,fn); newPerson.name = name; newPerson.age = 30; return newPerson; }; let hojin = Person("류호진"); // (3)
전역 실행 컨텍스트 전역 메모리 fn: { getName : fn , getAge : fn } (1)
Person: fn (2)
hojin: (3)먼저, fn이라는 라벨을 만들고 객체를 연결해 줍니다. 그 후, Person 라벨에 함수바디를 연결해 주고, Person의 결과값을 가지는 hojin이라는 변수를 만들어 줍니다.
let fn = { getName() { return this.name }, getAge() { return this.age } }; function Person(name){ // (2) let newPerson = {}; // (3) Object.setPrototypeOf(newPerson,fn); newPerson.name = name; newPerson.age = 30; return newPerson; }; let hojin = Person("류호진"); // (1)
전역 실행 컨텍스트 전역 메모리 Person("류호진"); (1) fn: { getName : fn , getAge : fn }
Person: fn
hojin:함수 실행 컨텍스트 지역 메모리 newPerson = {} (3) name : "류호진" (2)
newPerson : {} (3)Person함수가 호출되면 실행 컨텍스트가 만들어지고 name이라는 매개변수에 류호진이라는 값이 할당 될 것입니다. 그 후, 함수 바디가 실행되면 newPerson에 빈 객체가 할당 됩니다.
let fn = { getName() { return this.name }, getAge() { return this.age } }; function Person(name){ let newPerson = {}; Object.setPrototypeOf(newPerson,fn); // (1) newPerson.name = name; // (2) newPerson.age = 30; // (2) return newPerson; }; let hojin = Person("류호진");
전역 실행 컨텍스트 전역 메모리 Person("류호진"); fn : { getName : fn , getAge : fn }
Person : fn
hojin :함수 실행 컨텍스트 지역 메모리 Object.setPrototypeOf(newPerson,fn) name : "류호진"
newPerson : {
name : "류호진",
age : 30,
__proto__ : fn
}Object.setPrototypeOf라는 메소드를 통해 이 객체의 프로토타입을 fn 객체로 연결해 주게 됩니다. newPerson의 Prototype은 fn객체가 되는 것입니다. __proto__라는 특수속성 라벨을 이용하여 fn을 참조 하게 됩니다. 그 후, newPerson에 name속성을 만들고 값을 류호진으로 할당합니다. age도 같은 동작을 반복합니다.
let fn = { getName() { return this.name }, getAge() { return this.age } }; function Person(name){ let newPerson = {}; Object.setPrototypeOf(newPerson,fn); newPerson.name = name; newPerson.age = 30; return newPerson; // (1) }; let hojin = Person("류호진"); // (1)
전역 실행 컨텍스트 전역 메모리 fn : { getName : fn , getAge : fn }
Person : fn
hojin : {
name : "류호진",
age : 30,
__proto__ : fn
} (1)그리고 newPerson객체가 반환되어 hojin에 할당되고 실행컨텍스트는 종료 됩니다.
let fn = { getName() { return this.name }, getAge() { return this.age } }; function Person(name){ let newPerson = {}; Object.setPrototypeOf(newPerson,fn); newPerson.name = name; newPerson.age = 30; return newPerson; }; let hojin = Person("류호진"); hojin.getName(); // (1)
전역 실행 컨텍스트 전역 메모리 hojin.getName() fn : { getName : fn , getAge : fn }
Person : fn
hojin : {
name : "류호진",
age : 30,
__proto__ : fn
}함수 실행 컨텍스트 지역 메모리 이후, hojin.getName을 실행하게 되면 객체에 getName함수를 찾게 됩니다. 하지만 getName은 당연히 찾을 수 없을 것이고 자바스크립트 엔진은 __proto__ 라벨을 통해 프로토타입에서 찾게 됩니다. 프로토타입 내부에서 getName을 발견하면 함수실행 컨텍스트가 생성되고 그 후 이름을 반환하며 종료되게 될 것입니다.
결론적으로, 프로토타입으로 객체를 만드는 방법은 객체 생성을 위한 빈 객체를 만들고, 프로토타입은 연결하고, 속성값을 할당해주고 반환하는 일련의 과정이 필요하다는 것을 알 수 있습니다.
이러한 일련의 작업들을 자동으로 해주는 new 키워드를 예시와 함께 살펴보겠습니다.
function Person(name) { // (1) this.name = name; this.age = 30; } Person.prototype.getName = function() () { return this.name; } Person.prototype.getAge = function() () { return this.age; } let hojin = new Person("류호진"); hojin.getName();
전역 실행 컨텍스트 전역 메모리 Person : fn (1) function Person(name) { this.name = name; this.age = 30; } Person.prototype.getName = function() () { // (1) return this.name; } Person.prototype.getAge = function() () { // (1) return this.age; } let hojin = new Person("류호진"); // (2) hojin.getName();
전역 실행 컨텍스트 전역 메모리 Person : {
prototype : {
getName : fn
getAge: fn
}
} (1)
hojin : (2)Person에 함수바디를 연결합니다. Person은 함수이자 객체임으로 이 객체 타입에는 프로토타입이라는 빈 객체가 있습니다. 여기에 getName과 getAge라는 속성을 추가하고 함수 바디를 연결합니다. 그리고 Person의 결과값을 가지는 hojin이라는 변수를 만듭니다.
추가정보 : 자바스크립트에서 함수는 일급 객체 이다. (추후 따로 정리하겠습니다)
function Person(name) { this.name = name; this.age = 30; } Person.prototype.getName = function() () { return this.name; } Person.prototype.getAge = function() () { return this.age; } let hojin = new Person("류호진"); // (1) hojin.getName();
전역 실행 컨텍스트 전역 메모리 new Person() (1) Person : {
prototype : {
getName : fn
getAge: fn
}
}
hojin :함수 실행 컨텍스트 지역 메모리 name : "류호진" (1)
this: {} (1)그리고 Person함수를 실행시키는데 이때 new를 붙여 실행시킵니다. 실행되었으니 name 매개변수에 류호진을 할당합니다. 아까는 Person 객체 내부에 newPerson객체를 직접 만들었습니다. new 키워드를 이용해서 생성할때는 this라는 빈객체를 만들 것입니다.
function Person(name) { this.name = name; this.age = 30; } Person.prototype.getName = function() () { return this.name; } Person.prototype.getAge = function() () { return this.age; } let hojin = new Person("류호진"); // (1) hojin.getName();
전역 실행 컨텍스트 전역 메모리 new Person() Person : {
prototype : {
getName : fn
getAge : fn
}
}
hojin :함수 실행 컨텍스트 지역 메모리 name : "류호진"
this: {
__proto__ : {
getName : fn
getAge : fn
}
} (1)그리고 이 객체의 프로토타입을 Person의 Prototype으로 __proto__속성을 통해 할당해줍니다.
function Person(name) { this.name = name; // (1) this.age = 30; // (1) } Person.prototype.getName = function() () { return this.name; } Person.prototype.getAge = function() () { return this.age; } let hojin = new Person("류호진"); hojin.getName();
전역 실행 컨텍스트 전역 메모리 new Person() Person : {
prototype : {
getName : fn
getAge : fn
}
}
hojin :함수 실행 컨텍스트 지역 메모리 name : "류호진"
this: {
name : "류호진"
age : 30
__proto__ : {
getName : fn
getAge : fn
}
} (1)그 후 this 객체에 류호진이라는 name과 30이라는 age를 할당합니다.
전역 실행 컨텍스트 전역 메모리 Person : {
prototype : {
getName : fn
getAge : fn
}
}
hojin : {
name : "류호진"
age : 30
__proto__ : {
getName : fn
getAge : fn
}
}이후 hojin에는 위와 같이 값이 할당되게 됩니다. 결국 setPrototypeOf를 통해 직접 구현하였을 때와 같은 모양을 가지게 되는 것을 볼 수 있습니다.
결론적으로, new의 역할은 인스턴스 생성을 위해 this라는 이름의 빈객체를 만들고, this객체에 프로토타입을 연결해준 뒤 속성값을 할당하여 반환하는 것입니다.
DeepDive By 프로토타입(DeepDive By Prototype)
프로토타입
- 자바스크립트는 프로토타입 기반의 언어이며, 프로토타입의 구조는 크게 Prototype Object와 Prototype Link로 이루어져 있다. Prototype Object 내부에는 생성되었던 함수를 가르키고 있는 constructor와 Prototype Link인 __proto__로 이루어져 있다.
우리가 Concept에서 봤던 내용의 구조는 위의 그림과 같은 구조로 이루어져 있는 것을 볼 수 있습니다. 또한 __proto__라는 특수한 속성을 통해서 프로토타입과 연결된다고 말씀드렸습니다. 여기서 __proto__는 객체가 생성될떄의 조상이었던 프로토타입을 가르킵니다. 그럼 예를 들어 하나 보겠습니다.
예시
function Person(name) { this.name = name; this.age = 30; } Person.prototype.getName = function() { return this.name; } Person.prototype.getAge = function() { return this.age; } let hojin = new Person("류호진"); hojin.test;
이러한 코드가 있다면, 가장 먼저 Person객체를 확인합니다.
확인했는데 없다면 __proto__속성을 통해 Prototype을 확인합니다. 그 후 최상위의 Object까지 프로토타입을 탐색합니다. Object까지 탐색했을때 아무것도 못찾으면 return 값으로 undefined를 출력합니다.
이러한 프로토타입의 구조 때문에 모든 객체는 Object의 자식이라고 불리며, 우리는 Object의 toString과 같은 속성을 사용할 수 있는 것입니다. 아래 그림과 함께 보시면 좀 더 이해가 쉬울 것이라 생각됩니다.
결론적으로, 모든 객체의 최상위 프로토타입은 내장 Object.prototype이며 해당 최상위 객체 까지 찾지 못하면 프로토타입 체인 탐색은 종료 된다고 할 수 있습니다.
우리는 오늘 프로토타입에 대해서 자세히 알아 보았습니다. 코어 자바스크립트의 내용을 점점 알아 갈수록 프레임워크 등을 이해하는데도 많은 도움이 될 것이라고 생각합니다.
참고 : NHN FRONTEND CONFERENCE
자바스크립트 완벽가이드(도서)
반응형'frontend > javascript&web' 카테고리의 다른 글
자바스크립트 this (2) 2022.02.18 브라우저 저장소( 로컬 스토리지, 세션 스토리지, 쿠키 ) (0) 2022.02.17 이벤트 루프(Event Loop) (1) 2022.02.15 스코프(Scope) (0) 2022.02.09 호이스팅(Hoisting)과 클로저(Closure) (0) 2022.02.08