객체 생성은 일반적으로 객체 리터럴에 의해 생성합니다.
이 외에도 객체는 생성자 함수를 통해서도 생성할 수 있습니다.
생성자 함수를 통해 객체를 생성할 땐 new
연산자와 생성자 함수
를 호출하여 생성합니다.
이렇게 생성된 객체를 인스턴스라고 합니다.
JavaScript에서는 아래와 같은 빌트인 생성자 함수를 제공합니다.
code>
const sample = new Object();
console.log(sample);
const objString = new String('test');
console.log(objString);
const objNumber = new Number(10);
console.log(objNumber);
const objFunction = new Function('x', 'return x + x');
console.log(objFunction);
const objArray = new Array(1, 2, 3);
console.log(objArray);
const objDate = new Date();
console.log(objDate);
result>
{}
String {
'0': 't',
'1': 'e',
'2': 's',
'3': 't',
length: 4,
__proto__: {**}
}
[Number: 10] {
__proto__: {**}
}
ƒ anonymous()
[ 1, 2, 3 ]
2022-06-12T09:49:28.297Z
객체 리터럴의 직관적이고 간편한 객체 생성 방식이 있음에도 불구하고 생성자 함수를 쓰는 이유가 있습니다.
동일한 프로퍼티를 갖는 객체를 여러 개 생성할 때, 생성자 함수의 장점이 드러납니다.
생성자 함수를 활용하면 동일한 프로퍼티를 매번 기술하지 않고도 인스턴스 생성을 위한 클래스처럼 사용할 수 있습니다.
code>
// 객체 리터럴
const person1 = {
name: 'hyeonsik',
callName() {
return this.name;
}
}
const person2 = {
name: 'nick',
callName() {
return this.name;
}
}
// 생성자 함수
function Person(name) {
this.name = name;
this.callName = function() {
return this.name;
}
}
const person1 = new Person('hyeonsik');
const person2 = new Person('nick');
new 연산자와 생성자 함수가 호출되면 다음과 같이 동작이 이루어집니다.
this
바인딩this
반환this
반환함수 생성자를 통해 객체를 생성하는 방법에 대해 다뤄보았습니다.
하지만 정의된 모든 함수를 생성자로 사용할 순 없습니다.
함수 객체는 일반 객체와는 다르게 호출이 가능합니다.
이는 내부 메서드 [[Call]]
에 의해 가능합니다.
따라서 모든 함수 객체는 [[Call]]
이라는 내부 메서드를 가지고 있으며, 호출 가능하고, 일반 함수로서 호출되면 [[Call]]
메서드가 호출됩니다.
이 메서드를 가진 함수를 callable이라고 합니다.
일부 함수 객체는 내부 메서드 [[Construct]]
를 가지고 있습니다.
이 메서드를 가진 함수를 constructor라고 하고, 이 메서가 없는 함수를 non-constructor라고 합니다.
함수 선언문, 함수 표현식으로 정의된 함수
화살표 함수, 메서드 축약 표현으로 정의된 함수
new연산자와 함께 생성자로 사용이 가능한 함수는 constructor인 경우입니다.
new.target이란 생성자 함수가 new
연산자 없이 호출되는 것을 방지하기 위해 ES6에서 지원합니다.
new.target
은 호출된 함수가 new
연산자와 함께 호출되었는지 확인합니다.
이 때, 생성자 함수로써 호출되었으면 new.target
은 함수 자신을 가리킵니다.
반면에 일반 함수로써 호출되었으면 new.target
은 undefined
입니다.
new.target
은 함수를 생성자 함수로 호출하고자 할 때, new
연산자와 함게 호출되지 않으면 재귀를 통해 생성자 함수로 호출할 수 있습니다.
function Person(name) {
if (!new.target) {
return new Person(name);
}
this.name = name;
this.callName = function() {
return this.name;
};
}
하지만 new.target
은 ES6 이하 버전이나 IE에서 지원하지 않으므로 스코프 세이프 생성자 패턴을 통해 대체하는 것도 가능합니다.
function Person(name) {
if (!(this instanceof Person)) {
return new Person(name);
}
this.name = name;
this.callName = function() {
return this.name;
};
}
빌트인 생성자 중, Object, Function은 위와 같이 new
연산자 없이 호출된 생성자는 new
연산자와 함께 호출된 것과 동일한 결과를 보여줍니다.
하지만 String, Number, Boolean 생성자는 new
연산자가 없으면 해당 타입의 값을 반환합니다.