prototype은 자바스크립트의 객체지향성을 지탱하는 개념이다. 또 일반적인 객체지향 언어와 구분하는 개념이다. prototype은 말 그대로 객체의 원형이 된다. JS에서는 prototype으로 상속을 구현할 수 있다. JS ES6부터 class 키워드가 사용되었지만, class도 이 prototype의 개념을 벗어나지 않는다.
JS에서 Prototype이란 명칭은 2가지를 각각 가리킨다. 이 두 가지를 구분할 수 있어야 한다.
JS에서 Prototype을 이용하여, "인스턴스 생성"과 "Class 원형과 인스턴스의 연결"을 어떻게 이뤄내는지 살펴보자.
function Person(name, first, second) {
this.name = name;
this.first = first;
this.second = second;
}
function Person(){}
함수는 statement의 일종이지만, JS에서 함수는 독특한 "객체"다. 객체이기 때문에 new
키워드를 사용해서 함수를 표현할 수도 있다. var Person = new Function()
함수를 호출할 때 new
키워드를 사용하면, 그 함수는 단순한 함수가 아니라 생성자로서 호출된다.
function Person() {}
var obj = new Person();
console.log(typeof Person); //=> function
console.log(typeof obj); //=> object
Person
의 타입은 function이지만, obj
의 타입은 object다.
var name = "default name";
function Person(name) {
if (this.name) {
console.log(this.name);
} else {
this.name = name;
console.log(this.name);
}
}
Person("cho"); //=> default name
var obj = new Person("cho"); //=> cho
Person()
을 그냥 호출하면, this는 글로벌 오브젝트를 참조한다.[[Scope]]
가 window가 되고 이것을 외부 렉시컬 참조에 삽입했기 때문이다.new
키워드로 호출하면, this는 함수 그 자체에 바인딩된다.function Person(name, age) {
this.name = name;
this.age = age;
}
var kim = new Person("kim", 29);
kim
은 name
과 age
를 가진 객체가 된다.function Person(name, first, second) {
this.name = name;
this.first = first;
this.second = second;
}
Person
이라는 Function Object가 생성된다.Person.prototype
이라는 객체도 추가로 생성된다. 이것은 Prototype Object 라고 불린다. 이것이 클래스 원형의 역할을 하게 된다.그리고 위에서 말했던 프로퍼티들은 상대방을 참조하고 있다.
function object에는 프로퍼티 이름이 prototype인 프로퍼티가 있으며, prototype이라는 프로퍼티가 참조하는 것은 prototype obejct다. 이름이 겹쳐서 헷갈릴 수 있음
__proto__
프로퍼티 & prototype
프로퍼티var kim = new Person("kim", 10, 20);
var cho = new Person("cho", 20, 30);
new
키워드가 합쳐지면서, kim과 cho에 Person (함수)객체와 같은 새로운 객체가 생성된다.__proto__
라는 프로퍼티가 생긴다. 이 프로퍼티는 Person의 Prototype Object
를 참조한다.function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.name = "default name";
Person.prototype.age = "default age";
var kim = new Person("kim", 29);
console.log(Person.prototype === kim.__proto__); //=> true
console.log(Person.prototype === kim.__proto__);
.__proto__
프로퍼티로 Person의 Prototype Object
를 참조하고,.prototype
.이라는 Person의 Prototype Object
를 참조JS에서는 함수를 생성자로 쓰게되면, Prototype Object라는 것이 생긴다. Prototype Object가 클래스 객체 역할을 하게된다.
즉, 객체지향에서는 클래스안에 생성자 함수를 두지만, JS에서는 생성자와 클래스를 분리했다고 생각하면 된다.
객체지향에서 인스턴스들은 클래스의 메소드를 공유하거나, 클래스 원형의 데이터를 인스턴스에서 사용하기도 한다.
new
를 통해 생성되는 객체는 __proto__
프로퍼티로, 생성자는 prototype
프로퍼티로 prototype Object(Person.prototype) 을 참조한다.constructor
라는 프로퍼티로 생성자 (function Person) 를 참조한다.prototype link란 prototype chain이라고도 불린다. 스코프 체인의 원리와 비슷하다.
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.getName = function () {
console.log(this);
return this.name;
};
var cho = new Person("조병건", 28);
var kim = new Person("김병건", 18);
console.log(cho); //=> {name : 조병건, age: 28}
console.log(kim); //=> {name : 김병건, age :18}
console.log(cho.getName()); //=> 조병건
console.log(kim.getName()); //=> 김병건
Person.prototype.getName = function(){...}
cho
,kim
객체에는 getName이라는 메소드가 없다.cho.getName
과 kim.getName
은 정상적으로 동작한다.cho
와 kim
객체에는 getName
이라는 메소드가 없는데 어떻게 식별자 해결이 동작할까?__proto__
(prototype property) 가 참조하는 객체로 올라가서 식별자 해결을 하게 된다.__proto__
가 참조하는 것은 현재 Person.prototype Object이므로, getName에 대한 식별자 해결이 가능하다.cho.getName
이 호출되면, getName을 위한 실행 컨텍스트를 만든다. 이때, getName 호출문 앞에 위치한 cho
라는 객체를 this 바인딩 컴포넌트로 참조한다.cho
오브젝트로 가서 name
이라는 식별자에 대한 식별자 해결을 하게되고 값을 리턴하게 된다.객체지향에서는 상속이란 개념이 있다. JS는 Prototype을 이용해서 어떻게 상속을 구현했을까
function First(v) {
this.first = "first";
}
function Second() {
this.second = "second";
}
function Third() {
this.third = "third";
}
First.prototype.get = function () {
console.log(this.first, this.second, this.third);
};
Second.prototype = new First();
Third.prototype = new Second();
var obj = new Third();
obj
가 실제적으로 들고 있는 프로퍼티는 third
뿐이지만, 마치 부모 클래스가 있는 것 처럼, second
와 first
속성을 갖게 된다.(스코프 체인에 의하여) 이런 방식으로 상속을 구현한다.