Front-End/JavaScript
[JavaScript] 생성자 함수
sihyeong
2022. 10. 29. 00:02
생성자
- new 연산자와 함께 호출하여 객체를 생성하는 함수를 말한다.
- 인스턴스를 생성, 생성된 인스턴스를 초기화 한다.
- 인스턴스를 생성하고 반환하는 코드가 없어도 자바스크립트 엔진은 암묵적인 처리를 통해 인스턴스를 생성하고 반환한다.
- 암묵적으로 빈 객체가 생성된다. 이 객체는 this에 바인딩 된다. 이 처리는 런타임 이전에 실행됨
- this에 바인딩 된 인스턴스는 생성자 함수에 기술된 코드가 한줄씩 실행되며 프로퍼티나 메서드를 추가하며 초기화 된다.
- 모든 처리가 끝나면 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환된다.
- this가 아닌 다른 객체를 명시적 반환하면 암묵적 this 객체는 반환되지 못하고, return문에 명시한 객체가 반환된다.
function Circle(radius){
this.radius = radius;
return 100; // 명시적으로 원시값 반환 -> 무시됨 ,그리고 암묵적으로 this 반환됨
}
const circle = new Circle(1);
console.log(circle); // Circle { radius: 1 }
장점
- 객체를 생성하기 위한 템플릿처럼 생성자 함수를 사용하여 프로퍼티 구조가 동일한 객체 여러 개를 간편하게 생성 가능
함수
- 함수는 객체이므로 일반 객체와 동일하게 동작 가능, 일반 객체가 가지고 있는 내부 슬롯과 내부 메서드를 모두 가지고 있음
- 일반 객체와의 다른점은 일반 객체는 호출 불가능, 함수는 호출 가능하다.
- 호출이 가능한 이유는 함수 객체만을 위한 [[Environment]], [[FormalParameters]] 등 내부슬롯, [[Call]], [[Construct]] 같은 내부 메서드를 추가로 가지고 있기 때문임
function test() {}
test.prop = 10;
test.testMethod = function(){
console.log(this.prop);
};
test.testMethod(); // 10
// 함수는 객체와 동일하게 프로퍼티, 메서드 소유 가능
- 함수가 호출되면 함수 객체의 내부 메서드 [[Call]]이 호출됨
- new 연산자와 함께 생성자 함수로 호출되면 내부 메서드 [[Construct]]가 호출됨
- 모든 함수 객체는 [[Call]]을 갖지만, [[Construct]]를 모두 가지고 있진 않다.
- [[Construct]]를 가지고 있지 않은 함수는 ( ES6 메서드 축약 표현, 화살표 함수 )이다.
- 이들은 non-constructor로 생성자 함수로 사용이 불가능하다.
생성자 함수 호출 불가능 2가지
const arrowFunction = () => {}; // 화살표 함수
new arrowFunction(); // TypeError
const obj = {
x() {} // ES6 메서드 축약 표현, [[Construct]] 가지지 않음, 생성자 사용 불가
};
new obj.x(); // TypeError
일반 함수와 생성자 함수의 차이
- 특별한 형식적 차이 없다. new 연산자와 함께 함수를 호출하면 해당 함수는 생성자 함수로 동작함
- new 사용시 [[Construct]] 호출, 그외 일반적 호출시 [[Call]]이 호출되는 구조
function Circle(raidus){
this.radius = radius;
this.getDiameter = function(){
return 2 * this.radius;
};
};
const circle = Circle(5); // new 없으니 일반함수 호출, [[Call]] 호출
console.log(circle); // undefined, 생성자로 호출안했으니 반환되는 객체 없음
console.log(radius); // 5
console.log(getDiameter()); // 10
// 일반함수로 호출되었기 때문에 Circle의 this는 전역객체 window를 가리킴
circle.getDiameter(); // TypeError
생성자 함수 new 연산자 없이 호출 방지
- 위험성 회피를 위해 ES6에서 new.target을 지원한다.
function Circle(radius){
if(!new.target){ // 일반함수라면 new.target === undefined
return new Circle(radius); // 일반 함수면 new로 호출함
}
this.radius = radius;
this.getDiameter = function(){
return 2 * this.radius;
};
};
const circle = Circle(5); // new 안써도 자동으로 생성자함수로 new.target으로 생성자 만들어 처리
console.log(circle.getDiameter()); // 10
- 스코프 세이프 생성자 패턴 (scope-safe constructor)
function Circle(radius){
if(!(this instanceof Circle)){ // this가 Circle이 아니면 일반함수라서
return new Circle(radius); // 생성자함수로 강제 호출
}
this.radius = radius;
this.getDiameter = function(){
return 2 * this.radius;
};
};
const circle = Cirlce(5);
console.log(circle.getDiameter()); // 10
- this의 instance를 확인해서 생성자함수처럼 동작할 수 있음