자바스크립트 디자인 패턴 – 2. Constructor Pattern

이 글은 Essential JavaScript Design Patterns For Beginners, Volume 1. 를 보고 공부한 점을 정리한 글이며, 원문의 내용 전문이 아닌 일부의 내용을 담고 있습니다. 원문의 내용과 똑같은 부분도 있고 제가 알고 있는 내용을 따로 덧붙인 부분도 있으니 원문 – Essential JavaScript Design Patterns For Beginners, Volume 1. 을 꼭 보시기 바랍니다.

——————————————————————————————————————–

The Constructor Pattern

Constructor – 생성자 – 는 특별한 타입의 객체를 생성하는데 사용됩니다. 자바스크립트에서는 함수가 생성자의 역할을 할 수 있습니다. 그래서 객체를 생성하는데 사용되는 함수를 생성자 함수 – Constructor function – 이라고 합니다. 생성자 함수는 매개변수를 설정할 수 있고, 그것을 생성자 함수를 통해 생성될 객체의 프로퍼티들에 초기값을 주는데 사용할 수 있습니다.

Basic Constructors

자바스크립트에서 생성자 함수를 사용하는 방법은 인스턴스를 만드는 타당한 방법이라고 생각됩니다. 자바스크립트에는 다른 객체지향 언어에서 사용하는 클래스가 없지만 생성자 함수가 그와 유사한 역할을 할 수 있습니다. new 키워드와 함께 생성자 함수를 실행하면 객체를 생성할 수 있습니다. 여기에서 주의해야할 사항은 반드시 new 키워드와 함께 사용해야 한다는 점입니다. 생성자 함수도 일반적인 자바스크립트의 함수이기 때문에 new 키워드 없이도 실행시킬 수 있습니다. 그렇지만 그때에는 우리가 객체를 생성하기 위해 만들어놓은 목적과는 다른 작용을 하게 될 것입니다.

그러니까 new 키워드가 자바스크립트의 함수를 생성자 함수 역할을 하도록 만드는 것입니다. 생성자 함수 내부의 this 키워드는 새로 만들어질 객체를 가리키고 있습니다.

function Car(model, year, miles){
	this.model = model;
	this.year = year;
	this.miles = miles;
	this.toString = function(){
		return this.model + " has done " + this.miles + " miles";
	};
}

var civic = new Car("Honda Civic", 2009, 20000);
var mondeo = new Car("Ford Mondeo", 2010, 5000);

console.log(civic.toString());
console.log(mondeo.toString());

위 코드를 보시면 Car라는 생성자 함수를 사용해서 civic, mondeo 두 개의 객체를 만들었습니다. 각각의 객체는 생성할 때 인자로 넘겨준 값들을 model, year, miles 프로퍼티의 값으로 가지고 있을 것입니다. 그런데 위 방법에는 약간의 문제가 있습니다. toString 메서드는 new Car() 로 생성되는 새로운 객체에 하나씩 계속 생성이 될 텐데 이런 형태는 낭비적인 요소가 있다고 할 수 있습니다. 메서드의 내용을 보면 model이나 year 프로퍼티처럼 각 객체에 고유한 값이 들어가는 것이 아닙니다. 메서드를 하나만 만들고 공용으로 사용할 수 있다면 이상적일 것입니다.

Constructors With Prototypes

자바스크립트의 함수는 prototype이라는 프로퍼티를 가지게 됩니다. 자바스크립트 내장함수는 물론이고 개발자가 지금 바로 새로 만든 함수도 자동으로 prototype 프로퍼티를 가지게 됩니다. prototype 프로퍼티는 객체입니다. 즉, 자신의 프로퍼티를 가질 수 있습니다. prototype 객체는 생성자 함수에서 매우 유용하게 사용될 수 있는데, 생성자 함수로 생성된 객체들은 그 생성자 함수의 prototype 객체의 프로퍼티를 자신의(새로 생성된 객체) 프로퍼티에 접근하는 방식으로 접근할 수 있게 됩니다.

위의 Car 생성자 함수에서 toString 메서드를 Car 함수의 prototype 객체의 프로퍼티로 이동시켜 보겠습니다.

function Car(model, year, miles){
	this.model = model;
	this.year = year;
	this.miles  = miles;
}

/*
	Note here that we are using Object.prototype.newMethod rather than
	Object.prototype so as to avoid redefining the prototype object
*/
Car.prototype.toString = function(){
	return this.model + " has done " + this.miles + " miles";
};

var civic = new Car("Honda Civic", 2009, 20000);
var mondeo = new Car("Ford Mondeo", 2010, 5000);

console.log(civic.toString());

위 코드를 보시면 생성자 함수에는 this.toString … 의 형태로 toString 메서드가 정의되어 있지 않습니다. 대신 Car.prototype.toString … 의 형태로 toString 메서드가 prototype 객체의 프로퍼티로 되어 있습니다. 이렇게 만들어 놓아도 18라인에서 처럼 civic 객체에서 toString 메서드를 사용할 수 있습니다. 소스코드에는 나와 있지 않지만 mondeo 객체에서도 mondeo.toString() 처럼 사용할 수 있습니다.

Car 생성자 함수로 생성한 객체들은 모두 자신의 프로퍼티인 것 처럼 toString 메서드를 사용할 수 있습니다. 실제로 toString 메서드는 Car.prototype.toString 으로 한군데에 정의되어 있지만, Car 생성자 함수로 만든 모든 객체에서 사용할 수 있는 프로퍼티가 된 것입니다. 따라서 prototype을 사용하지 않을 때의 문제점인, 중복된 메서드를 계속 만드는 낭비를 막을 수 있습니다. prototype을 사용하면 또 좋은 점은 메서드를 수정할 일이 있을 때 prototype에 있는 코드를 수정하면, Car 생성자 함수로 만든 객체들에 모두 동시에 영향을 준다는 점입니다. toString 메서드의 소스코드가 각각의 객체에 직접 작성된 것이 아니고 각 객체들이 모두 Car.prototype.toString을 가리키고 있는 것이기 때문에 prototype을 수정하면 모든 객체의 메서드를 동시에 수정한 것과 같은 효과를 가지게 됩니다.

Side-note: Douglas Crockford는 생성자 함수명의 첫 글자는 대문자로 하는 방법을 추천하였습니다. 자바스크립트에서 일반 함수와 생성자 함수는 문법적으로 아무런 차이가 없습니다. 다만, 생성자 함수는 new 키워드와 함께 사용되었을 때 객체를 생성하게 된다는 기능적인 차이점이 있을 뿐입니다. 그래서 생성자 함수의 경우 함수명의 첫 글자를 대문자로 하는 규칙을 정하면, 일반 함수와 쉽게 구분할 수 있게 됩니다.

  • cheonjeongmin

    잘 읽어보고 가요 ^^

    • codefactory

      감사합니다..^^

  • http://www.eojji.com EOJJI

    대문자 객체생성함수