객체 생성 방법은 여러 가지가 있다. 이번에는 객체 리터럴로 생성하는 방법이 아닌, 생성자 함수를 사용하여 객체를 생성하는 방식에 대해 알아보도록 하겠다.
이때, 생성자 함수란 new 연산자와 함께 호출하여 객체를 생성하는 함수를 말한다. 생성자 함수에 생성된 객체를 인스턴스라고 한다. (빌트인)생성자 함수의 종류로는 Object, String, Number, Boolean, Function, Array, Date, RegExp, Promise 등이 있다.
Object 생성자 함수
new 연산자와 함께 Object 생성자 함수를 호출하면 빈 객체가 생성되고, 빈 객체를 생성한 이후에는 프로퍼티와 메서드를 추가할 수 있다.
// 빈 객체 생성
const person = new Object();
// 프로퍼티 추가
person.name = 'Mudryk';
person.sayHello = function() {
console.log('Welcome to ChelseaFC!! ' + this.name);
}
생성자 함수
객체를 생성하는 방식은 생성자 함수를 사용하는 것보다 객체 리터럴을 사용하는 것이 더 편하다. 그렇다면 생성자 함수를 사용하는 이유는 무엇인가? 이러한 궁금증들을 해소하며 생성자 함수에 대해서 더 자세히 알아보도록 하곘다.
객체 리터럴에 의한 객체 생성 방식의 문제점
객체 리터럴을 통해 객체를 생성하는 방식은 간편하지만, 단 하나의 객체만을 생성한다는 문제점이 있다. 동일한 객체를 가지는 객체를 여러 개 생성해야 하면 매번 같은 프로퍼티를 직접 작성해야 한다.
생성자 함수에 의한 객체 생성 방식의 장점
생성자 함수에 의한 객체 생성 방식은 템플릿(클래스)과 같이 생성자 함수를 사용하여 프로퍼티 구조가 동일한 여러 객체를 간편하게 생성 가능하다.
생성자 함수는 객체를 생성하는 함수이며, 일반 함수로 동작한다. 만약 생성자 함수를 정의하고 `new` 연산자와 함께 호출할 경우 해당 함수는 생성자 함수로 동작한다.
생성자 함수의 인스턴스 생성 과정
생성자 함수는 인스턴스를 생성하고 생성된 인스턴스를 초기화하는 역할을 담당한다. 생성자 함수가 인스턴스를 생성하는 과정은 다음과 같다.
- 인스턴스 생성과 this 바인딩: 런타임 이전에 암묵적으로 빈 객체가 생성되고, 생성된 빈 객체(인스턴스)는 this에 바인딩된다.
- 인스턴스 초기화: 생성자 함수에 적힌 코드가 실행되어 this에 바인딩된 인스턴스를 초기화한다.
- 인스턴스 반환: 생성자 함수 내부의 모든 처리가 완료되면 인스턴스가 바인딩된 this가 암묵적으로 반환된다. 이때, return문을 따로 명시할 경우 this가 반환되지 않고 return문에 명시된 객체가 반환된다.(원시 값을 반환하면 무시되고 this가 반환된다.) 따라서 생성자 함수 내부에서는 return문을 반드시 생략해야 한다.
내부 메서드 `[[Call]]`과 `[[Construct]]`
함수는 객체이므로 프로퍼티를 소유할 수 있고 메서드도 소유할 수 있다. 또한 함수는 일반 객체와 달리 호출이 가능하다. 그리고 특별히 일반 객체가 가지고 있는 내부 슬롯과 내부 메서드 이외에 함수 객체만을 위한 내부 슬롯과 내부 메서드를 추가로 가진다.
일반 함수로 호출되면 내부 메서드 [[Call]]이 호출되고 이를 callable이라 하며, new 연산자와 함께 생성자 함수로서 호출되면 내부 메서드 [[Construct]]가 호출되고 이를 constructor이라고 한다. 모든 함수 객체는 [[Call]]을 가지기에 호출 가능하다. 그러나, 모든 함수 객체가 [[Construct]]를 가지는 것은 아니다.
constructor와 non-constructor
함수 객체가 `[[Construct]]`를 가지면 constructor이라고 하고, 함수 객체가 `[[Construct]]`를 가지지 않으면 non-constructor라고 한다. 이는 함수 정의 방식에 따라서 constructor와 non-constructor로 구분된다. 일반 함수와 생성자 함수에 특별한 형식적 차이가 없다는 것은 알아두자
- constructor: 함수 선언문, 함수 표현식, 클래스(클래스도 함수이다.)
일반 함수 또는 생성자 함수로서 호출할 수 있는 객체이다. - non-constructor: 메서드(ES6 메서드 축약 표현), 화살표 함수
일반 함수로서만 호출할 수 있는 객체이다.
new 연산자와 new.target
new 연산자와 함께 함수를 호출할 경우, 해당 함수는 생성자 함수로 호출된다. 반대로, new 연산자 없이 생성자 함수를 호출하면 일반 함수로 호출된다. 즉, 함수가 생성자 함수로 호출된다는 것은 내부 메서드 [[Construct]]가 호출된다는 것을 의미한다. 이때, new 연산자와 함께 호출하는 함수는 반드시 Constructor이어야 한다.
생성자 함수가 new 키워드 없이 호출되면 전역 객체에 속성이 추가되어 전역 스코프를 오염시킬 수 있다. 이는 코드의 유지보수를 어렵게 하고 에러 발생 가능성을 높인다. 따라서 ES6에서는 생성자 함수가 new 연산자 없이 호출되는 것을 방지하기 위하여 new.target을 지원한다.
함수 내부에서 new.target 을 사용하면 new 연산자와 함께 생성자 함수로 호출되었는지 알 수 있다. 만약 new 연산자와 함께 생성자 함수로서 호출되면 함수 내부의 new.target 은 함수 자신을 가리킨다.
래퍼런스(Reference)
https://www.yes24.com/Product/Goods/92742567
https://guswlsakfls.tistory.com/84