상세 컨텐츠

본문 제목

[javascript] 생성자 함수

Web/Javascript

by 클리엘 클리엘 2020. 5. 21. 13:49

본문

1. 개요

 

생성자 함수는 객체를 만들 때 사용하는 함수라고 말할 수 있습니다. 일반적인 프로그래밍에서 클래스와 비슷한 개념(클래스는 밑에서 별도로 언급하겠습니다.)을 가지고 있습니다.

function MyCar(name, color, number) {
	this.name = name;
	this.color = color;
	this.number = number;
}

var mc = new MyCar('승용차', '파란색', '1234');

생성자 함수는 일반 함수와 구조가 동일하지만 내부에서 사용할 속성 등은 this키워드를 통해서 구분해줘야 합니다. 예제에서는 MyCar라는 생성자 함수를 통해 mc라는 인스턴스를 생성하였습니다.

 

생성자 함수의 인스턴스 개체를 생성할때는 new키워드를 사용하며 이는 개체의 개별적인 공간을 만들고 this키워드로 해당 개체를 가리켜 속성과 메서드 등을 호출할 수 있도록 합니다. 만약 new를 생략하게 되면 window객체에 속성을 정의한 것으로 처리되어 경우에 따라 원하는 방향으로 실행되지 않는 경우가 생길 수 있으므로 꼭 new키워드를 사용해 개체를 생성하시길 바랍니다.

 

참고로 특정 인스턴스 객체가 대상이 되는 생성자함수로부터 생성되었는지를 확인하려면 instanceof 키워드를 사용해 판별할 수 있습니다.

function MyCar(name, color, number) {
	this.name = name;
	this.color = color;
	this.number = number;
}

var mc = new MyCar('승용차', '파란색', '1234');

alert(mc instanceof MyCar);

예제에서 mc는 MyCar라는 생성자 함수로부터 생성된 인스턴스이므로 true를 출력합니다.

 

2. 메서드

function MyCar(name, color, number) {
	this.name = name;
	this.color = color;
	this.number = number;

	this.car_name = function() {
		alert(this.name);
	};
}

var mc = new MyCar('승용차', '파란색', '1234');
mc.car_name();

생성자 함수는 내부에 필요한 메서드를 추가할 수 있습니다. 이 경우에도 물론 this키워드를 통해서 메서드를 정의해야 하며 이때 메서드는 각 인스턴스 개체마다 개별적으로 소유하게 되고, 해당 메서드는 인스턴스를 통해서 호출될 수 있게 됩니다.

 

메서드는 각 개체마다 개별적으로 생성된다는 특징때문에 필요하다면 특정 개체에 대해 메서드를 바꾸는 것도 가능합니다.

function MyCar(name, color, number) {
	this.name = name;
	this.color = color;
	this.number = number;

	this.car_name = function() {
		alert(this.name);
	};
}

var mc1 = new MyCar('승용차', '파란색', '1234');
var mc2 = new MyCar('승용차', '파란색', '1234');

mc1.car_name();

mc2.car_name = function() {
	alert(this.color);
}

mc2.car_name();

mc1와 mc2라는 인스턴스를 생성했고 둘다 name속성 값을 출력하는 car_name함수를 가지게 됐지만 mc2개체의 car_name메서드를 새롭게 정의해 color값이 출력될 수 있도록 하였습니다.

 

3. 프로토타입

 

모든 개체마다 동일한 메서드를 보유한다는 특징은 개체가 상당 수 늘어나면 메모리 등의 리소스를 낭비하는 상황으로 이어질 수 있습니다. 그래서 동일한 메서드를 개별적으로 생성하는 것이 아니라 메서드가 정의된 하나의 영역을 두고 각 개체마다 이 영역을 공유할 수 있도록 하는 경우도 있는데 이것을 프로토타입이라고 합니다.

function MyCar(name, color, number) {
	this.name = name;
	this.color = color;
	this.number = number;
}

MyCar.prototype.car_name = function() {
	alert(this.name);
};

var mc1 = new MyCar('승용차', '파란색', '1234');
var mc2 = new MyCar('승용차', '파란색', '1234');

mc1.car_name();
mc2.car_name();

프로토타입은 함수에 자동으로 만들어지는 공간으로서 이 공간에 메서드를 정의하면 각 개체마다 메서드를 공유하여 사용하게 됩니다.

 

4. 캡슐화

 

MyCar 생성자 함수는 number라는 속성을 가지고 있고, 이 속성에는 숫자(혹은 숫자로 변환될 수 있는 문자열)만 입력이 가능하다는 규칙이 존재한다고 가정해 보겠습니다. 이 상태에서 인스턴스를 생성한뒤 개체에서 number라는 속성을 다음과 같이 변경하는 시도가 생긴다면

function MyCar(name, color, number) {
	this.name = name;
	this.color = color;
	this.number = number;
}

var mc = new MyCar('승용차', '파란색', '1234');
mc.number = 'abc';

alert(mc.number);

아무런 오류없이 정상적으로 처리됨을 알 수 있습니다. 때문에 필요하다면 생성자 함수에서 잘못된 값이 입력되는 경우를 차단하기 위한 장치를 마련해야 하는데 이를 캡슐화라고 합니다.

function MyCar(name, color, number) {
	this.name = name;
	this.color = color;
	var mynumber = number;

	this.get_number = function () {
		return mynumber;
	};

	this.set_number = function (n) {
		if (isNaN(Number(n))) {
			alert('숫자만 입력해 주세요.');
			mynumber = 1234;
		}
		else {
			mynumber = n;
		}
	};
}

var mc = new MyCar('승용차', '파란색', '1234');
mc.set_number('abc');
alert(mc.get_number());

예제에서는 set_number함수를 통해서 mynumber변수의 값을 바꿀 수 있도록 하였는데 set_number함수는 매개변수로 전달되는 값을 확인하여 숫자로 바꿀 수 없으면(숫자가 아니면) 오류 메시지를 내고 1234 값이 강제로 들어갈 수 있도록 하는 처리가 마련되어 있습니다. 이로 인해 잘못된 값을 전달하면 오류를 발생시키고 mynumber변수로 값이 전달되지 않을 것입니다.

 

get_number함수 또한 mynumber의 값을 반환하도록 하는 함수로서 필요하다면 별도의 처리를 통해 반환되는 값의 형태를 가공할 수 있습니다.

 

참고로 해당 함수에 정의된 set_number함수는 값을 설정한다고 하여 세터(setter), get_number함수는 값을 가져온다고 하여 게터(getter)라 부르기도 합니다.

 

5. 상속

 

새로운 생성자 함수를 정의할때 기존의 다른 생성자 함수의 모든 걸 그대로 물려받는 경우를 '상속'이라고 표현합니다.

function MyCar(name, color, number) {
	this.name = name;
	this.color = color;
	var number = number;

	this.get_number = function () {
		return number;
	};

	this.set_number = function (n) {
		if (isNaN(Number(n))) {
			alert('숫자만 입력해 주세요.');
			number = 1234;
		}
		else {
			number = n;
		}
	};
};

function MyCar2(name, color) {
	this.base = MyCar;
	this.base(name, color, '1234');

	this.get_name = function() {
		return this.name;
	};
};

var mc2 = new MyCar2('트럭', '녹색');
mc2.set_number(4567);

alert(mc2.get_number());
alert(mc2.get_name());

예제에서는 MyCar라는 생성자 함수를 상속받아 MyCar2라는 새로운 생성자 함수를 작성하였습니다. 상속에 대한 실직적인 처리는

this.base = MyCar;

에서 진행되었으며

this.base(name, color, '1234');

구문을 통해 MyCar의 생성자함수에 대한 초기화 과정을 처리하고 있습니다. 여기서 base는 MyCar를 뜻하지만 base라는 이름 자체는 어떤 것으로 해도 무관합니다.

 

MyCar2에서는 MyCar를 그대로 물려받았으므로 MyCar에서 정의된 메서드인 set_number와 get_number를 자유롭게 호출할 수 있고 실제 MyCar2의 인스턴스 객체인 mc2에서는 MyCar2에서 set_number와 get_number메서드를 정의하지 않았음에도 이를 정상적으로 호출하는 것을 확인할 수 있습니다. 물론 get_name메서드처럼 자신만의 새로운 메서드를 만들어 호출하는 것도 가능합니다.

 

주의할 점은 prototype은 생성자함수 본체와는 분리되어 있으므로 만약 prototype까지도 모두 가져와야 한다면 다음과 같은 별도의 구분을 추가해야 합니다.

function MyCar2(name, color) {
	this.base = MyCar;
	this.base(name, color, '1234');

	this.get_name = function() {
		return this.name;
	};
};

MyCar2.prototype = MyCar.prototype;
MyCar2.prototype.constructor = MyCar2;

MyCar2의 prototype을 MyCar의 protoype으로 대체하고 있으며 Constructor를 통해 prototype 생성자 함수를 재정의 하였습니다.

 

참고로 instanceof 키워드를 사용하면 어떤 객체가 특정 생성자 함수로부터 만들어 졌는지를 확인할 수 있습니다.

alert(mc2 instanceof MyCar);

결과는 true인데 mc2의 생성자 함수는 본래 MyCar2이지만 MyCar로부터 상송되었으므로 MyCar로부터 만들어진 객체로 인식됨을 알 수 있습니다.

 

6. 클래스

 

자바스크립트도 클래스개념을 도입함에 따라 클래스를 사용할 수 있습니다. 대부분 생성자 함수와 비슷하므로 생성자 함수를 알고 있다면 어렵지 않게 접근할 수 있습니다.

class MyCar {
	constructor(name, color, number) {
		this.name = name;
		this.color = color;
		this.number = number;
	}

	get_name() {
		return this.name;
	}
};


var mc = new MyCar('승용차', '녹색', 1234);
alert(mc.get_name());

클래스는 class라는 키워드를 사용해 정의합니다. 생성자 함수에서는 직접 함수명에서 매개변수형태로 필요한 값을 전달받았는데 클래스에서는 contstructor를 통해 class안에서 초기화 함수를 생성하며 필요한 함수도 class내부에서 직접 정의됩니다.

 

생성자 함수에서 특정 변수에 값을 붙이려면

this.set_number = function (n) {
  if (isNaN(Number(n))) {
  	alert('숫자만 입력해 주세요.');
  	number = 1234;
  }
  else {
  	number = n;
  }
};

와 같은 메서드를 생성하여

mc.set_number('1234');

와 같이 메서드를 호출하는 방법을 이용했지만 클래스부터는 공식적으로 get과 set을 지원합니다.

class MyCar {
	constructor(name, color, number) {
		this.name = name;
		this.color = color;
		this.number = number;
	}

	get_name() {
		return this.name;
	}

	get Number() {
		return this.number;
	}

	set Number(n) {
		this.number = n;
	}
};


var mc = new MyCar('승용차', '녹색', 1234);

mc.Number = 4567;
alert(mc.Number);

예제에서 get와 set의 Number는 값을 설정할때와 값을 가져올 때 자동으로 호출되어 number변수를 다룰 수 있도록 합니다.

class MyCar {
	constructor(name, color, number) {
		this.name = name;
		this.color = color;
		this.number = number;
	}

	get_name() {
		return this.name;
	}

	get Number() {
		return this.number;
	}

	set Number(n) {
		this.number = n;
	}
};

class MyCar2 extends MyCar {
	constructor(name, color, number) {
		super(name, color, number);
	}

	get Number() {
		return this.number;
	}
};


var mc = new MyCar('승용차', '녹색', 1234);
var mc2 = new MyCar2('트럭', '파란색', 4567);

alert(mc.Number);
alert(mc2.Number);

클래스에 대한 상속은 위 예제처럼 extends [클래스명]의 형식을 통해 지정한 클래스에서 상속받을 수 있도록 할 수 있습니다. 또한 자식 클래스에서 부모의 생성자를 호출하려면 생성자 함수에서 base가 아닌 super를 통해 값을 넘겨야 합니다.

'Web > Javascript' 카테고리의 다른 글

[javascript] 브라우저 관련 객체  (0) 2020.05.26
[javascript] 기본 내장 객체 (표준 내장 객체)  (0) 2020.05.26
[javascript] 생성자 함수  (0) 2020.05.21
[javascript] 객체  (0) 2020.04.30
[javascript] 함수  (0) 2020.03.27
[javascript] 반복문  (0) 2020.03.24

관련글 더보기

댓글 영역