본문 바로가기
Resource/JavaScript & TypeScript

[JavaScript] 프로토타입 (Prototype)

by 우창욱 2023. 11. 16.

자바스크립트는 프로토타입 기반(prototype-based)으로 객체지향 프로그래밍(OOP, Object Oriented Programming)을 지원하는 프로그래밍 언어입니다. 자바스크립트는 객체지향 프로그래밍의 핵심 개념인 상속(Inheritance)을 프로토타입 기반으로 구현하며 코드 재사용을 줄입니다.

 

const testObj = {};

console.log(testObj.__proto__); // [Object: null prototype]{}
console.log(testObj.__proto__ === Object.prototype); // true

 

__proto__와 prototype

 

자바스크립트에서는 객체의 프로토타입에 접근하기 위해 __proto__라는 접근자 프로퍼티를 사용해서 현재 객체의 프로토타입을 확인할 수 있습니다. __proto__ 접근자 프로퍼티는 모든 객체에 존재하는 프로퍼티입니다.

function PersonModel(name, year) {
  this.name = name;
  this.year = year;
}

console.log(PersonModel.prototype);

console.dir(PersonModel.prototype, {
  showHidden: true
}
//<ref *1> {
//  [constructor]: [Function: PersonModel] {
//    [length]: 2,
//    [name]: 'PersonModel',
//    [arguments]: null,
//    [caller]: null,
//    [prototype]: [Circular *1]
//  }
//}

const changuk = new PersonModel('우창욱', 1998);

 

생성자 함수를 사용하여 객체의 프로토타입을 확인해보면, IdolModel 프로토타입의 생성자 프로퍼티(constructor)는 IdolModel을 가리키는 것을 확인할 수 있습니다. 이를 순환 참조(Circular Reference)라고 합니다.

IdolModel 객체를 new 키워드로 인스턴스화하여 생성된 yuJin 객체는 자동으로 생성된 __proto__ 접근자 프로퍼티를 갖게 되고, __proto__IdolModel.prototype을 가리키게 됩니다.

 

또한 IdolModel.__proto__Function.prototype을 가리키고, Function.prototype.__proto__Object.prototype을 가리킵니다. 결국 new 키워드로 생성된 yuJin 객체는 Object까지 상속받게 됩니다. 이렇게 상속이 이어져 있는 것을 프로토타입 체인(Prototype Chain)이라고 하고, 프로토타입 체인으로 도달할 수 있는 모든 객체의 최상위 객체는 Object 입니다.

 

프로퍼티 섀도잉

function PersonModel(name, year) {
  this.name = name;
  this.year = year;

  this.sayHello = function () {
    return '안녕하세요 저는 인스턴스 메서드입니다!';
  };
}

PersonModel.prototype.sayHello = function () {
  return '안녕하세요 저는 prototype 메서드입니다!';
};

const changuk = new PersonModel('우창욱', 1998);
console.log(changuk.sayHello()); // 안녕하세요 저는 인스턴스 메서드입니다!

delete changuk['sayHello'];

console.log(changuk.sayHello()); // 안녕하세요 저는 prototype 메서드입니다!

 

객체에서 정의한 메서드가 있는 경우, 프로토타입으로 정의한 메서드가 가려지게 되는데 이를 프로퍼티 섀도잉 이라고합니다. 객체에 정의한 메서드를 삭제하게 되면 프로토타입으로 정의한 메서드가 다시 나타나게 됩니다.

결국 프로토타입의 메서드를 덮어쓰는 게 아닌 인스턴스의 메서드를 추가하는 것이라고 할 수 있습니다.