[JS] 프로토타입(Prototype)

jiseong·2021년 8월 16일
0

T I Learned

목록 보기
33/291
post-thumbnail

자바스크립트는 클래스기반이 아닌 프로토타입을 기반으로 하는 객체 기반 언어이다.

프로토타입(Prototype)

프로토타입(프로토타입 객체)은 자바스크립트에서 객체간의 상속을 구현하는 메커니즘으로 모든 객체는 프로토타입을 가지며 해당 프로토타입의 프로퍼티와 메소드를 상속받아 사용할 수 있다.

일반 객체

객체 리터럴( { } )로 생성된 객체

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]]는 부모 역할을 담당하는 프로토타입 객체
    • 함수 객체의 [[Prototype]]는 Function.prototype
  • 2) prototype 프로퍼티
    • prototype 프로퍼티를 가질 수 있는 것은 오직 함수 뿐이며, 이 프로퍼티는
      이 함수로 생성될 객체의 부모 역할을 담당하는 객체를 가리킨다.
      let newPerson = new Person('jiseong');
      console.dir(newPerson.__proto__ === Person.prototype);   // true

      Person 함수객체 자체의 prototype 프로퍼티는 ?

      • 자신을 가리킨다.
        console.dir(Person.prototype);

prototype.constructor

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로 표현된 것이다.

그렇다면 위에서 언급된 프로토타입 체인에 대해서 그림으로 알아보자.


Prototype chain

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의 constructorPerson() 생성자함수를 가리킨다.
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을 의미한다.


원시 타입의 [[Prototype]]

자바스크립트에는 총 7개의 데이터 타입이 있으며 원시 타입을 제외한 모든 것은 객체 타입이라고 했는데 그렇다면 원시 타입은 [[prototype]]을 가지고 있지 않음과 동시에 prototype의 프로퍼티나 메소드를 사용할 수 없을 것이다.

하지만 아래와 같이 원시 타입 또한 이상없이 잘 작동하는 것을 볼 수 있다.

let year = 2021;

console.log(year.toString());

이는 원시 타입이 프로퍼티에 접근하려고 할 때, 자바스크립트 엔진은 래퍼 객체로 임시 변환하여 메소드를 제공해주기 때문에 가능한 일이다. 그리고 사용된 후에는 래퍼 객체를 소멸시키기 때문에 기존의 객체와는 달리 프로퍼티나 메소드를 직접 추가할 수 없다.


Reference

0개의 댓글