자바스크립트에서는 생성자 함수가 new 연산자 없이 호출되는 것을 방지
하기 위해 ES6에서 new.target
을 지원한다. 하지만 IE에서는 new.target을 지원하지 않아서 스코프 세이프 생성자 패턴
을 사용한다.
그렇다면 new.target은 무엇이고 스코프 세이프 생성자 패턴은 무엇일까? 먼저 스코프 세이프 생성자에 대해 설명하겠다.
스코프 세이프 패턴은 생성자 함수가 new와 함께 호출되지 않았을 때 this가 해당 함수 프로토타입에 연결되어 있지 않음을 이용한 패턴이다.
따라서 this instance 생성자 함수 식별자
가 false일 시 new 연산자와 함께 해당 함수를 재귀 호출함으로써, 반드시 생성자 함수로서 호출할 수 있게끔 약속한다.
// Scope-Safe Constructor Pattern
function Circle(radius) {
// 생성자 함수가 new 연산자와 함께 호출되면 함수의 선두에서 빈 객체를 생성하고 this에 바인딩한다.
// 이때 this와 Circle은 프로토타입에 의해 연결된다.
// 이 함수가 new 연산자와 함께 호출되지 않았다면 이 시점의 this는 전역 객체 window를 가리킨다.
// 즉, this와 Circle은 프로토타입에 의해 연결되지 않는다.
if (!(this instanceof Circle)) {
// new 연산자와 함께 재귀 호출하여 인스턴스를 반환한다.
return new Circle(radius);
}
this.radius = radius;
this.getDiameter = function () {
return 2 * this.radius;
}
}
// new 연산자 없이 생성자 함수를 호출하여도 생성자 함수로서 호출된다.
const c1 = Circle(5);
console.log(c1.getDiameter()); // 10
```
생성자 함수가 new 연산자 없이 호출되는 것을 방지하기 위해 ES6에서는 new.target 문법을 지원한다.
new.target은 constructor인 모든 함수 내부에서 암묵적인 지역 변수와 같이 사용되며 메타 프로퍼티라고 불린다.
new 연산자와 함께 생성자 함수로서 호출되면 함수 내부의 new.target은 함수 자신
을 가리킨다. new 연산자 없이 일반 함수로서 호출된 함수 내부의 new.target은 undefined
다.
따라서 함수 내부에서 new.target을 사용하여 생성자 함수로서 호출됐는지 확인하여 그렇지 않은 경우 new 연산자와 함께 재귀 호출을 통해 생성자 함수로서 호출할 수 있다.
// 생성자 함수
function Circle(radius) {
// 해당 함수가 new 연산자와 함께 호출되었다면 new.target은 함수 자신인 Circle을 바인딩한다.
// 이 함수가 new 연산자와 함께 호출되지 않았다면 new.target은 undefined이다.
if (!new.target) {
// new 연산자와 함께 생성자 함수를 재귀 호출하여 생성된 인스턴스를 반환한다.
return new Circle(radius);
}
this.radius = radius;
this.getDiameter = function () {
return 2 * this.radius;
};
}
// new 연산자 없이 생성자 함수를 호출하여도 new.target을 통해 생성자 함수로서 (재귀)호출된다.
const c1 = Circle(5);
console.log(c1.getDiameter()); // 10
(docs)