자바스크립트는 클래스기반이 아닌 프로토타입을 기반으로 하는 객체 기반 언어이다.
프로토타입(프로토타입 객체)은 자바스크립트에서 객체간의 상속을 구현하는 메커니즘
으로 모든 객체는 프로토타입을 가지며 해당 프로토타입의 프로퍼티와 메소드를 상속받아 사용할 수 있다.
객체 리터럴( { }
)로 생성된 객체
let user = {
name: 'jiseong',
};
console.log(user.hasOwnProperty('name')); // true
console.dir(user);
위의 코드에서 user 객체가 hasOwnProperty 메소드를 가지고 있지 않아도
메소드를 쓸 수 있었던 이유는 Object.prototype을 상속받고 있기 때문에 Object.prototype의 메소드 hasOwnProperty를 호출하여 가능한 것이다. 그리고 이렇게 부모의 프로퍼티나 메소드를 찾아가는 행위를 프로토타입 체인
이라고 한다.
[[Prototype]]인터널 슬롯의 값
은 Prototype(프로토타입) 객체
를 말하며 __proto__
프로퍼티를 이용하면 프로토타입 객체를 참조할 수 있다.
console.log(user.__proto__ === Object.prototype); // true
console.dir(user.__proto__);
자바스크립트 엔진은 객체 리터럴로 객체를 생성하는 코드를 만나면 내부적으로 Object() 생성자 함수를 사용하여 객체를 생성한다.
자바스크립트에서 함수도 결국 객체
이다.
function Person(name) {
this.name = name;
}
console.dir(Person);
위의 결과를 보면 함수 객체에는 1)[[Prototype]]말고도
2)prototype 프로퍼티
가 존재
한다.
1) [[Prototype]]
함수 객체의 [[Prototype]]는 Function.prototype
2) prototype 프로퍼티
이 함수로 생성될 객체의 부모 역할을 담당하는 객체
를 가리킨다.let newPerson = new Person('jiseong');
console.dir(newPerson.__proto__ === Person.prototype); // true
Person 함수객체 자체의 prototype 프로퍼티는 ?
- 자신을 가리킨다.
console.dir(Person.prototype);
prototype의 프로퍼티 중 constructor라는 것이 존재한다. 이는 자식 객체의 관점에서 부모 객체를 나타내는 프로퍼티
이다.
function Person(name) {
this.name = name
}
let newPerson = new Person('jiseong');
console.dir(newPerson);
위의 결과로 newPerson의 부모 객체는 결국 Person.prototype이기 때문에 newPerson.[[prototype]].constructor(= Person.prototype.constructor)는 Person() 생성자함수
를 가리킨다.
여기서
[[Prototype]] Person
이 아닌[[Prototype]] Object
라 표현 된 것은 함수 또한 객체이기 때문에 Object로 표현된 것이다.
그렇다면 위에서 언급된 프로토타입 체인에 대해서 그림으로 알아보자.
function Person(name){
this.name = name;
}
let newPerson = new Person('jiseong');
console.dir(newPerson.__proto__);
newPerson.__proto__
는 Person.prototype
을 가리킨다.console.dir(newPerson.__proto__.constructor);
Person.prototype의 constructor
는 Person() 생성자함수
를 가리킨다.console.dir(newPerson.__proto__.__proto__);
Person.prototype의 __proto__
는 Object.prototype
을 가리킨다.console.dir(newPerson.__proto__.constructor.__proto__);
Person() 생성자함수의 __proto__
는 Function.prototype
을 가리킨다. 이는 함수 객체의 [[Prototype]]는 Function.prototype이기 때문이다.console.dir(newPerson.__proto__.constructor.__proto__.__proto__);
Function.prototype의 __proto__
는 Object.prototype
을 가리킨다. 이는 함수 또한 객체이기 때문이다.
그렇다면 Object.prototype의 __proto__
는 무엇일까? Object.prototype 객체는 프로토타입 체인의 종점이며 이는 곧 null을 의미한다.
자바스크립트에는 총 7개의 데이터 타입이 있으며 원시 타입을 제외한 모든 것은 객체 타입이라고 했는데 그렇다면 원시 타입은 [[prototype]]을 가지고 있지 않음과 동시에 prototype의 프로퍼티나 메소드를 사용할 수 없을 것이다.
하지만 아래와 같이 원시 타입 또한 이상없이 잘 작동하는 것을 볼 수 있다.
let year = 2021;
console.log(year.toString());
이는 원시 타입이 프로퍼티에 접근하려고 할 때, 자바스크립트 엔진은 래퍼 객체로 임시 변환하여 메소드를 제공해주기 때문에 가능한 일
이다. 그리고 사용된 후에는 래퍼 객체를 소멸시키기 때문에 기존의 객체와는 달리 프로퍼티나 메소드를 직접 추가할 수 없다.