[JS] 프로토타입 객체

생성자 안에서 메서드를 정의하는 방식의 문제점

function Circle(center, radius) {
  this.center = center;
  this.radius = radius;
  this.area = function () {
    return Math.PI * this.radius ** 2;
  };
}
const c1 = new Circle({ x: 0, y: 0 }, 2.0);
const c2 = new Circle({ x: 0, y: 1 }, 4.0);
const c3 = new Circle({ x: 1, y: 0 }, 5.0);

Circle 안에 면적을 구하는 area 메서드를 정의하였다. Circle 생성자로 생성한 인스턴스 c1,c2,c3는 같은 메서드를 포함하게 된다.

이는 같은 작업을 하는 메서드를 인스턴스 갯수만큼 생성하는 것이므로,
그만큼 메모리 낭비가 일어나게 된다.

프로토타입 객체

이러한 문제는 프로토타입 객체에 메서드를 정의하여 해결할 수 있다.

function Circle(center, radius) {
  this.center = center;
  this.radius = radius;
}
Circle.prototype.area = function () {
  return Math.PI * this.radius ** 2;
};
const c1 = new Circle({ x: 0, y: 0 }, 2.0);
const c2 = new Circle({ x: 0, y: 1 }, 4.0);
const c3 = new Circle({ x: 1, y: 0 }, 5.0);

console.log(c1.area()); // 12.566370614359172

__proto__ 프로퍼티는 그 객체에게 상속을 해 준 부모 객체를 가리킨다.
따라서 객체는 __proto__ 프로퍼티가 가리키는 부모 객체의 프로퍼티를 사용할 수 있다.

인스턴스 c1, c2, c3는 생성자로 Circle을 사용하였고, __proto__는 생성자인 Circle의 prototype object를 가리키고 있다. 따라서, 인스턴스들은 Circle 프로토타입 객체가 갖고 있는 area 메서드를 사용할 수 있게 된다.
이렇게 함으로써 인스턴스에 메서드를 추가하지 않고도, 인스턴스들은 메서드를 사용할 수 있다. 결과적으로 메모리 낭비를 막을 수 있다.

프로토타입 객체의 프로퍼티

함수가 정의될 때 함수 객체Prototype Object 이 생긴다.

  1. 함수 객체는 prototype 프로퍼티를 갖고 있다.
    • prototype property는 Prototype Object를 가리킨다.
    • 생성된 Prototype object는 함수 객체의 prototype 프로퍼티를 통해 접근할 수 있다.
    • 이 때, prototype object는 함수 객체만 갖고 있다. 단일 객체가 만들어질 때는 생기지 않는다.
  2. Prototype Object는 constructor__proto__ 를 갖고 있다.
    • constructor는 생성된 함수 객체의 참조를 갖고 있다.
    • __proto__Prototype Link 로서 생성자의 Prototype Object를 가리킨다.
    • 프로토타입 객체의 __proto__는 기본적으로 Object.prototype을 가리킨다. 즉, 프로토타입 객체의 프로토타입은 Object.prototype이다.

프로토타입 객체 교체

  • 함수 객체의 프로토타입 프로퍼티를 교체할 때는 교체할 객체에 constructor 프로퍼티로 생성자의 참조를 대입해야 한다.
function Circle(center, radius) {
  this.center = center;
  this.radius = radius;
}
Circle.prototype = {
  constructor: Circle,
  area() {
    return Math.PI * this.radius ** 2;
  },
};

const c1 = new Circle({ x: 0, y: 0 }, 2.0);
console.log(c1.area()); // 12.566370614359172

인스턴스가 프로토타입을 상속받는 시기

  • 인스턴스의 프로토타입은 생성자가 인스턴스를 생성할 때 갖고 있던 프로토타입 객체이다.
  • 인스턴스 생성 후, 생성자의 prototype 프로퍼티를 다른 객체로 교체하여도 인스턴스의 프로토타입은 바뀌지 않는다.
function Circle(center, radius) {
  this.center = center;
  this.radius = radius;
}
const c1 = new Circle({ x: 0, y: 0 }, 2.0);
Circle.prototype = {
  constructor: Circle,
  area() {
    return Math.PI * this.radius ** 2;
  },
};

console.log(c1.area()); // TypeError: c1.area is not a function

c1 인스턴스의 프로퍼티는 Circle이 생성되는 시점의 프로퍼티를 상속받게 된다. c1인스턴스 생성 후, Circle의 프로토타입 프로퍼티를 교체하여도 교체한 객체로부터는 프로퍼티를 상속받지 않는다.

  • 인스턴스 생성 후 프로토타입 객체에 프로퍼티를 추가한다면, 인스턴스는 추가된 프로퍼티를 사용할 수 있다.
function Circle(center, radius) {
  this.center = center;
  this.radius = radius;
}
const c1 = new Circle({ x: 0, y: 0 }, 2.0);
Circle.prototype.area = function () {
  return Math.PI * this.radius ** 2;
};

console.log(c1.area()); // 12.566370614359172

출처

좋은 웹페이지 즐겨찾기