본문 바로가기
JavaScript

생성자 패턴 (new 키워드와 prototype 객체)

by enai 2019. 8. 21.

애플리케이션이 복잡해질수록 모듈화가 필요하다.

자바스크립트도 객체로 비슷한 속성과 행위를 묶어서 모듈화 할 수 있다.

이렇게 좀 더 객체지향적인 방법으로 표현하는 방법을 생성자(constructor) 패턴을 통해 이해해보자.

 

 

먼저, 자바스크립트의 객체는 객체 리터럴로 쉽게 표현할 수 있다.

 

var healthObj = {
  name : "달리기",
  lastTime : "PM10:12",
  showHealth : function() {
    console.log(this.name + "님, 오늘은 " + this.lastTime + "에 운동을 하셨네요");
  }
}

 

이러한 코드를 객체리터럴이라고 하는데,

이 healthObj의 형태를 가진 객체가 여러 개 필요할 때가 있다.

name이 "개발자"이고, 운동을 한 시간 lastTime이 AM9:30인 사람에 대한 객체가 필요하다고 가정해보겠다.

 

var healthObj2 = {
  name : "개발자",
  lastTime : "AM9:30",
  showHealth : function() {
    console.log(this.name + "님, 오늘은 " + this.lastTime + "에 운동을 하셨네요");
  }
}

 

필요한 정보를 담은 healthObj2라는 객체를 새로 만들어 처리할 수 있다.

하지만 이렇게 하면 코드에 불필요한 중복이 발생하고, 새로운 데이터가 추가될 때마다 비슷한 객체들을 계속해서 만들어 두는 것은 매우 비효율적이다.

또한, 유지보수할 때도 수정이 필요한 중복되는 코드를 모두 수정하려면 힘들어질 것이다.

이를 해결하기 위한 방법으로, 생성자와 new와 prototype에 대해 정리해보겠다.

 

 

 

 

1. 객체를 동적으로 생성하기 (new 키워드)

 

function Health(name, lastTime){
    this.name = name;
    this.lastTime = lastTime;
    this.showHealth = function(){
        return this.name + "님 오늘은 " + this.lastTime + "에 운동을 하셨네요";
    }
}

var healthObj = new Health("달리기","PM10:00");

 

위 코드의 healthObj에 Health {name: "달리기", lastTime: "PM 10:00", showHealth: function(){... }} 이런 객체 리터럴 형태의 객체 데이터가 담겨 있을 것이다.

 

만약 var healthObj = Health("달리기","PM10:00");라고 했다면, healthObj는 undefined였겠지만,

new 키워드로 Health 함수를 불러내면서 저런 객체를 생성할 수 있었다. 그래서 Health를 생성자라고 한다. (생성자는 보통 대문자로 시작한다.)

 

new 키워드가 Health 함수를 불렀을 때 객체를 반환했던 건,

new로 Health 함수를 호출하면 그 Health 함수 안의 this를 반환하게 되기 때문이다. return this;가 내부에서 실행되는 것과 같이 동작한다고 생각하면 된다.

그래서 Health 함수의 인자로 받은 데이터가 this에 저장되어 return 되었기 때문에, 저런 결과 데이터를 받을 수 있었다.

 

이렇게 new 키워드로 객체를 동적으로 생성할 수 있는 방법을 알아보았다.

 

 

하지만 showHealth 함수는 여전히 객체 생성할 때마다 생성돼서 불필요한 메모리 공간을 차지하고 있다.

 

 

 

 

2. prototype 사용하기

 

생성자들은 prototype이라는 것들을 다 가지고 있다. 생성자의 prototype에 어떤 메서드를 넣어두면, 이 생성자로 만들어진 객체들은 prototype의 공간을 공유하고 있으므로 해당 메서드를 모두 사용할 수 있다.

 

function Health(name, lastTime) {
  this.name = name;
  this.lastTime = lastTime;
}

//prototype에 속성 추가
Health.prototype.showHealth = function() {
  console.log(this.name + "," + this.lastTime);
}

const h = new Health("달리기", "PM10:12");
console.log(h);  //크롬개발자도구를 열고 이 부분이 어떻게 출력되는지 확인해보세요
h.showHealth();

 

Health.prototype.xxx로 Health라는 생성자의 prototype에 속성을 추가하여 어떤 메서드를 생성할 수 있다.

위 코드처럼 showHealth를 Health가 아닌 protootype 객체에 추가했다.

 

이제 new 키워드로 Health 객체를 생성하여 h 변수에 담았다.

크롬 개발자 도구 콘솔에서 console.log(h);를 실행해보면,

 

 

이런 결과가 나온다.

h 객체 속성 중 __proto__라는 속성이 보일 것이다.

이것이 크롬 개발자 도구에서 prototype 객체를 나타내는 속성 이름인데, 위 사진처럼 Health의 prototype에 showHealth 함수 속성이 있음을 알 수 있다.

 

const h = new Health("달리기", "PM10:12");
const h2 = new Health("개발자", "AM9:20");
console.log(h.showHealth === h2.showHealth); //결과 값: true

 

이렇게 h, h2 두개의 객체를 생성했을 때, 각 객체의 showHealth 메서드는 참조하는 값이 같음을 알 수 있다.

(===는 일치연산자로, 비교되는 두 데이터의 타입이 다르면 false를 반환한다.)

h, h2 모두 prototype 안의 showHealth를 불러오기 때문이다.

 

도식으로 표현하면 아래 사진과 같다.

JAVA의 상속과 같은 느낌이 난다.

상속을 위한 건 아니지만, 이 prototype을 이용하여 상속 구조를 만들 수도 있다고 한다.

 

 

 

 

 

출처)

edwith 부스트코스 웹 프로그래밍

- 생성자패턴

댓글