[Programming] - 모던자바스크립트 17. 생성자 함수에 의한 객체 생성


객체를 여러개 생성해야할때 아래와 같은 방식은 매우 비효율적이다.

const circle1 = {
	radius: 5,
	getDiameter() {
		return 2 * this.radius;
	}
}

const circle2 = {
	radius: 10,
	getDiameter() {
		return 2 * this.radius;
	}
}

...

생성자 함수를 통해 객체를 생성 할 수 있다.

function Circle(radius) {
	this.radius = radius;
	this.getDiameter = function () {
		return 2 * this.radius;
	};
}

const circle1 = new Circle(5);
const circle2 = new Circle(10);

new 키워드 없이 사용하면 일반 함수처럼 동작한다.

this


여기서 this를 알아보자.

this의 의미는 함수 호출 방식에 따라 달라진다.

일반 함수 ⇒ window 객체

function foo() {
	console.log(this);
}

foo(); //window

메서드 ⇒ 메서드를 호출한 객체

const obj = { foo };
obj.foo(); //obj

생성자 함수 ⇒ 생성될 인스턴스

const inst = new foo(); // inst

생성자 함수 내부에서 this는 암묵적으로 빈 객체 {}가 생성되어있다. 또한 암묵적으로 this를 반환한다.

여기서 주의할 점은 생성자 함수에 명시적 return이 있으면 문제가 발생될수 있다. 빈 객체 반환 : this반환이 무시된다. 빈 객체가 반환된다. 원시값 반환 : 원시값을 무시하고 this가 정상적으로 반환된다.

내부 메서드


함수 객체는 일반 객체와 같이 내부 슬롯과 내부 메서드를 모두 가지고 있다.

여기에 추가적으로 [[Call]]과 [[Construct]] 2가지 내부 메서드를 가지고있다.

일반 객체와 다르게 함수 객체는 호출이 가능함으로 Call 내부 메서드가 호출된다.

function foo() {}

foo(); // [[Call]]이 호출된다.

new foo(); // [[Construct]]가 호출 된다.

[[Call]] 메서드는 함수 객체라면 무조건 가지고 있다.

하지만 [[Construct]] 메서드는 있는 경우와 없는 경우가 있다.

[[Construct]] 메서드가 없는 경우 생성자 함수로써 동작할 수 없다.

생성자 비-생성자 구분


[[Construct]] 메서드가 없는 경우는 어떤 경우일까?

  • [[Construct]] 가 있는 경우 : 함수 선언문, 함수표현식, 클래스(클래스도 함수다)
  • [[Construct]] 가 없는 경우 : 메서드(ES6 메서드 축약 표현), 화살표 함수
//함수 선언문
function foo() {}
//함수 표현식
const bar = function() {};

const baz = {
	x: function() {}
}; //이런 경우도 x에 일반 함수가 정의되어서 메서드로 인정하지 않는다.

new foo();
new bar();
new baz.x();

//화살표 함수
const arrow = () => {};
new arrow(); //Error

//ES6 메서드 축약 표현
const obj = {
	x() {}
};
new obj.x(); //Error

new.target


new.target은 this와 유사하게 모든 함수 내부에서 사용가능한 메서드 프로퍼티이다. (IE는 지원안한다.)

new.target으로 생성자 함수로 호출되었는지 확인이 가능하다.

  • new.target이 undefined라면 일반 함수 호출
  • new.target이 함수 자신을 가르키면 생성자 함수

아래와 같이 응용이 가능하다.

	function Circle(radius) {
		if(!new.target) {
			return new Circle(radius);
		}
		
		this.radius = radius;
		this.getDiameter = function () {
			return this.radius * 2;
		}
};

const circle = Circle(10);//실수로 일반함수로 호출해도 생성자 함수로 대응한다.