Object 생성자 함수
new와 Object 생성자 함수를 호출하면 빈 객체를 생성하여 반환한다.
빈 객체를 생성한 후에 프로퍼티나 메서드를 추가하여 완성할 수 있다.
Object 외에도 String, Number, Boolean, Function, Array, Date, RegExp, Promise 등의 빌트인 생성자 함수를 제공한다.
생성자 함수
객체 리터럴로 객체 생성하는 것의 문제점
하나의 객체만 생성하므로 동일한 프로퍼티를 갖는 객체를 여러개 갖는 경우 매번 같은 프로퍼티를 기술하기 때문에 비효율적이다.
생성자 함수에 의한 객체 생성 방식의 장점
프로퍼티, 메서드 구조가 같은 객체 여러개를 간편하게 생성할 수 있다.
function Circle(radius){
this.radius=radius;
this.getDiameter=function(){
return 2*this.radius;
}
}
const circle1=new Circle(3);
const circle2=new Circle(5);
console.log(circle1.getDiameter()); //6
console.log(circle2.getDiameter()); //10
new와 함수를 같이 호출하면 해당 함수는 인스턴스를 만드는 생성자 함수로 동작한다.
생성자 함수의 인스턴스 생성과정
- 인스턴스 생성과 this 바인딩이후 이 인스턴스는 this에 바인딩된다.
- 1번은 런타임 이전에 실행된다.
- 암묵적으로 빈 객체가 생성된다.
- 인스턴스 초기화
- 생성자 함수에 기술되어있는 코드가 한줄씩 실행되어 this에 바인딩되어있는 인스턴스를 초기화한다.
- 인스턴스 반환만약 this가 아닌 다른 객체를 반환하면 식별자에 해당객체가 반환된다.
function Circle(radius){ this.radius=radius; this.getDiameter=function(){ return 2*this.radius; } return {}; } const circle=new Circle(1); console.log(circle); //{}
- 생성자 함수의 모든 처리가 끝나면 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환된다.
만약 원시값을 반환한다면, 원시값은 무시되고 this가 반환된다.
따라서 생성자 함수 내부의 return은 반드시 생략한다.
내부메서드 [[Call]]과 [[Construct]]
함수도 객체이므로 함수 객체는 일반 객체가 가진 내부 슬롯과 내부 메서드를 몯두 가진다.
다만, 함수 객체는 호출될 수 있으므로 함수로서 동작하기 위한 [[Enviroment]], [[FormalParameters]]등의 내부 슬롯과 [[Call]], [[Construct]] 같은 내부 메서드를 추가로 가진다.
일반 함수로 호출하면 Call, 생성자 함수로 호출하면 Construct가 호출된다.
내부 메서드 Call을 갖는 객체를 callable이라하고, 내부 메서드 Construct를 갖는 함수객체를 constructor, 갖지않는 객체를 non-constructor라고 한다.
Call은 함수 객체라면 무조건 가져야 한다.
constructor와 non-constructor의 구분
constructor: 함수 선언문, 함수 표현식, 클래스
non-constructor: 메서드, 화살표 함수
다만, 메서드는 ES6의 축약 표현만 인정한다.
const foo={
x:function(){} //메서드 아님
}
const bar={
x(){} //메서드
}
new 연산자
new 연산자는 [[Construct]]를 호출한다.
단, 이때 함수는 constructor여야 한다.
일반 함수로 호출하면, 전역객체에 해당 프로퍼티와 메서드가 할당된다.
new.target
생성자 함수가 new 연산자 없이 호출되는 것을 방지하기위해 ES6에서는 new.target을 지원한다.
new.target은 메타 프로퍼티라고 부르며, IE에서는 지원되지 않는다.
new.target은 생성자 함수로서 호출될 경우 함수 자신을 가리킨다. 아닌 경우, undefined이다.
function Circle(radius){
if(!new.target){
return new Circle(radius)
}
this.radius=radius;
this.getDiameter=function(){
return 2*this.radius;
};
}
const circle=Circle(5);
console.log(circle.getDiameter);