Object 생성자 함수
생성자 함수
객체 리터럴에 의한 객체 생성 방식의 문제점
- 객체 리터럴을 사용하여 객체를 생성하면 직관적이고 간편 but 하나의 객체만 생성 ⇒ 동일한 프로퍼티를 갖는 객체 여러 개를 생성해야 하는 경우 매번 같은 프로퍼티를 기술해야해서 비효율적
생성자 함수에 의한 객체 생성 방식의 장점
- 프로퍼티 구조가 동일한 객체 여러 개를 간편하게 생성 가능 ⇒ 객체를 생성하는 템플릿st
function Circle(radius) {
this.radius = radius;
this.getDiameter = function() {
return 2 * this.radius;
}
}
// 인스턴스의 생성
const circle1 = new Circle(5);
const circle2 = new Circle(10);
- new 연산자와 함께 호출 시 생성자 함수로 동작하고, new 연산자가 없다면 일반 함수로 동작
생성자 함수의 인스턴스 생성 과정
- 생성자 함수의 역할 : 인스턴스 생성, 생성된 인스턴스 초기화 (인스턴스 프로퍼티 추가 및 초깃값 할당)
- 생성자 함수에 인스턴스를 생성하고 반환하는 코드가 없어도 자바스크립트 엔진이 암묵적인 처리를 통하여 인스턴스 생성 및 반환 ⇒ new 연산자 사용해서 생성자 함수
인스턴스 생성과 this 바인딩
- new 연산자와 함께 생성자 함수 호출 시 빈 객체가 생성되고, **this에 바인딩** 됨 ⇒ 생성자 함수 내부의 this가 생성자 함수가 생성할 인스턴스를 가리키는 이유 (this 바인딩은 런타임 이전에 실행)
인스턴스 초기화
- 생성자 함수에 기술되어 있는 코드가 한 줄씩 실행되어 this에 바인딩되어 있는 인스턴스 초기화
function Circle(radius) {
// 1. 암묵적으로 인스턴스가 생성되고 this에 바인딩 됨
// 2. this에 바인딩되어 있는 인스턴스 초기화
this.radius = radius;
this.getDiameter = function() {
return 2 * this.radius;
}
}
인스턴스 반환
- 생성자 함수 내부의 모든 처리가 끝나면 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환됨
function Circle(radius) {
// 1. 암묵적으로 인스턴스가 생성되고 this에 바인딩 됨
// 2. this에 바인딩되어 있는 인스턴스 초기화
this.radius = radius;
this.getDiameter = function() {
return 2 * this.radius;
}
// 3. 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환
}
// 인스턴스의 생성 (Circle 생성자 함수가 암묵적으로 this 반환)
const circle1 = new Circle(5);
- 만약 생성자 함수에서 명시적 객체를 반환한다면 this를 반환하지 않고 명시적 객체 반환하고, 원시값 반환시 원시값은 무시되고 this 반환 ⇒ 생성자 함수 내부에서 return 문 사용 X
내부 메서드 [[Call]]과 [[Construct]]
- 함수는 객체이지만 일반 객체와 다르게 호출 가능 ⇒ 일반 객체가 가지고 있는 내부 슬롯과 내부 메서드뿐만 아니라 [[Environment]], [[FormalParameters]] 등의 내부 슬롯, [[Call]], [[Construct]] 내부 메서드 가지고 있음
- 생성자 함수가 일반 함수로서 호출되면 함수 객체의 내부 메서드 **[[Call]]**이, new 연산자와 함께 생성자 함수로서 호출되면 [[Construct]] 가 호출됨
- 내부 메서드 **[[Call]]**을 갖는 함수 객체 ⇒ callable
- **[[Construct]]**를 갖는 함수 객체 ⇒ constructor
- **[[Construct]]**를 갖지 않는 함수 객체 ⇒ non-constructor
⇒ 함수는 무조건 호출할 수 있으므로 함수 객체는 반드시 callable이지만, 생성자 함수로서 동작 가능하면 constructor, 일반 함수로서만 동작 가능하다면 non-constructor
constructor과 non-constructor의 구분
- 자바스크립트 엔진은 함수 객체를 생성할 때 정의 방식에 따라 constructor와 non-constructor을 구분
- constructor : 함수 선언문, 함수 표현식, 클래스
function() {}
const bar = function() {};
const baz = {
x: function() {} // 프로퍼티 값으로 할당된 것은 일반 함수
}
new foo() {};
new bar() {};
new baz.x();
- non-constructor : 메서드 (ES6 메서드 축약 표현), 화살표 함수
- 이 함수들을 new 연산자와 함께 호출 시 에러 발생
const arrow = () => {};
new arrow(); // TypeError: arrow is not a constructor
const obj = {
x() {}
};
new obj(); // TypeError: arrow is not a constructor
new 연산자
- new 연산자와 함께 함수 호출하면 해당 함수는 생성자 함수로 동작 ⇒ 함수 객체의 내부 메서드 [[Call]]이 아닌 **[[Construct]]**가 호출됨
- new 연산자와 함께 호출되는 함수는 constructor이어야 함
- 생성자 함수는 일반 함수와 형식적 차이가 없기때문에 생성자 함수는 일반적으로 첫 문자를 대문자로 기술하는 파스칼 케이스로 명명하여 일반 함수와 구별
new.target
- 생성자 함수를 new 키워드 없이 호출한 경우에도 생성자 함수로서 호출할 수 있게 해줌
// 생성자 함수
function Circle(radius) {
// 이 함수가 new 연산자와 함께 호출되지 않았다면 new.target은 undefined
if (!new.target) {
return new Circle(radius)
}
this.radius = radius;
this.getDiameter = function() {
return 2 * this.radius;
}
}
// new 연산자 없이 생성자 함수를 호출하여도 new.target을 통해 생성자 함수로서 호출됨
const circle = Circle(5);
- new 연산자와 함께 생성자 함수에 의해 생성된 객체는 프로토타입에 의해 생성자 함수와 연결됨 ⇒ 생성자 함수가 new 연산자와 함께 호출됐는지 확인 가능
- 자바스크립트 빌트인 생성자 함수 중 Object와 Function은 new 연산자 없이 호출했을 때와 new 연산자와 함께 호출했을 때 모두 동일하게 동작
let obj = new Object();
console.log(obj); // {}
let obj = Object();
console.log(obj); // {}
let f = new Function('x', 'return x ** x');
console.log(f); // f anonymous(x) {return x ** x}
let f = Function('x', 'return x ** x');
console.log(f); // f anonymous(x) {return x ** x}
- 자바스크립트 빌트인 생성자 함수 중 String, Number, Boolean 생성자 함수는 new 연산자와 함께 호출하면 String, Number, Boolean 객체를 생성하여 반환하지만, new 연산자 없이 호출하면 문자열, 숫자, 불리언 값 반환
const str = String(123);
console.log(str, typeof str); // 123 string
const num = Number('123');
console.log(num, typeof num); // 123 number
const bool = Boolean('true');
console.log(bool, typeof bool); // true boolean