함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다.
따라서 생성자 함수로서 호출할 수 없는 함수, 즉 non-constructor인 화살표 함수와 ES6 메서드 축약 표현으로 정의한 메서드는 prototype 프로퍼티를 소유하지 않으며 prototype도 생성하지 않는다.
const Person = name => {this.name = name};
const obj = {foo(){}}
// 이런 경우는 prototype도 생성하지 않는다.
function Person(name){
this.name = name;
}
const me = new Person("Lee");
//결국 Person.prototype과 me.__proto__는 결국 동일한 프로토타입을 가리킨다.
console.log(Person.prototype === me.__proto__); //true
모든 Prototype은 constructor 프로퍼티를 갖는다. 이 constructor 프로퍼티는 prototype 프로퍼티로 자신을 참조하고 있는 생성자 함수를 가리킨다.
function Person(name){
this.name = name;
}
const Tester = new Person("tester");
console.log(Tester.constructor === Person); // true
Tester 객체는 Prototype의 constructor 프로퍼티를 통해 생성자 함수와 연결된다. Tester 객체는 constructor 프로퍼티가 없지만 Tester 객체의 프로토타입인 Person.prototype에는 constructor 프로퍼티가 있다. 따라서 me 객체는 프로토타입인 Person.prototype의 constructor 프로퍼티를 상속받아 사용할 수 있다.
리터럴 표기법에 의한 객체생성방식과 같이 명시적으로 new 연산자와 함께 생성자 함수를 호출하여 인스턴스를 생성하지 않는 객체 생성 방식도 있다.
//객체 리터럴
const obj = {};
//함수 리터럴
const add = function(a,b){return a+b};
//배열 리터럴
const arr = [1,2,3];
//정규 표현식 리터럴
const regexp =/is/ig;
리터럴 표기법에 의해 생성된 객체도 물론 프로토타입이 존재한다. 하지만 리터럴 표기법에 의해 생성된 객체의 경우 프로토타입의 constructor 프로퍼티가 가리키는 생성자 함수가 반드시 객체를 생성한 생성자 함수라고 단정할 수 없다.
///obj 객체는 객체 리터럴로 생성
## const obj = {};
//하지만 obj 객체의 생성자 함수는 Object 생성자 함수다.
console.log(obj.constructor === Object) // true
// 인스턴스 -> Foo.prototype -> Object.prototype 순으로 프로토타입 체인이 생성
class Foo extends Object{}
new Foo(); // Foo {}
//foo 함수는 함수 선언문으로 생성
function foo() { }
//하지만 constructor 프로퍼티를 통해 확인해보면 함수 foo의 생성자 함수는
// Function
console.log(foo.constructor === Function) // true
리터럴 표기법에 의해 생성된 객체도 상속을 위해 프로토타입이 필요하다. 따라서 리터럴 표기법에 의해 생성된 객체도 가상적인 생성자 함수를 갖는다.
프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재한다.
결국 모든 객체는 생성자 함수와 연결되어 있다.
프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성된다.
생성자 함수로서 호출할 수 있는 함수, 즉 constructor는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 Prototype도 더불어 생성된다.
console.log(Person.prototype); // {constructor :f }
//생성자 함수
function Person(name){
this.name = name;
}
// 화살표 함수는 non-constructor 다.
const Person = name => {
this.name = name;
}
// non-constructor는 프로토타입이 생성되지 않는다.
console.log(Person.prototype); // undefined
함수 선언문은 런타임 이전에 자바스크립트 엔진에 의해 먼저 실행된다. 따라서 함수 선언문으로 정의된 Person 생성자 함수는 어떤 코드보다 먼저 평가되어 함수 객체가 된다. 이때 프로토타입도 더불어 생성된다. 생성된 프로토타입은 Person 생성자 함수의 prototype 프로퍼티에 바인딩 된다.
생성된 프로토타입은 오직 constructor 프로퍼티만을 갖는 객체다.
Object, String, Number, Function ,Array , RegExp, Date, Promise 등과 같은 빌트인 생성자 함수가 생성되는 시점에 프로토타입이 생성된다.
모든 빌트인 생성자 함수는 전역 객체가 생성되는 시점에 생성된다. 생성된 프로토타입은 빌트인 생성자 함수의 Prototype 프로퍼티에 바인딩 된다.
function Person(name){
this.name = name;
}
//프로토타입 메서드
Person.prototype.sayHello = function(){
console.log(`HI! My name is ${this.name}`);
};
const me = new Person("Lee");
// hasOwnProperty는 Object.prototype의 메서드다.
console.log(me.hasOwnProperty("name")); // true
Person 생성자 함수에 의해 생성된 me 객체는 Object.prototype의 메서드인 hasOwnProperty를 호출 할 수 있다. 이것은 me 객체 뿐만 아니라 Object.prototype도 상속받았다는 것을 의미한다.
me 객체의 프로토타입은 Person.prototype이다. Person.prototype의 프로토타입은 Object.prototype이다.
프로토타입의 프로토타입은 언제나 Object.prototype이다.
자바스크립트는 객체의 프로퍼티에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티가 없다면 [[Prototype]] 내부 슬롯의 참조를 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다.
이를 프로토타입 체인이라 한다. 프로토타입 체인은 자바스크립트가 객체지향 프로그래밍의 상속을 구현하는 메커니즘이다.
프로토타입 체인의 최상위에 위치하는 객체는 언제나 Object.prototype이다. 따라서 모든 객체는 Object.prototype을 상속받는다. Object.prototype을 프로토타입 체인의 종점이라 한다.