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를 확인해서 생성자함수처럼 동작할 수 있음