생성자 함수는 일반 함수와 차이는 없고 대문자로 시작하며 new
키워드를 사용해서 객체를 생성합니다.
const obj = new Object();
자바스크립트는 Object
생성자 함수 이외에도 String, Number, Boolean, Function, Array, Date, Promise
등 빌트인 생성자 함수를 제공합니다.
생성자 함수와 일반 함수와는 기술적으로는 차이가 존재하지 않지만 생성자 함수는 두 가지를 관례적으로 지켜야 합니다.
new
연산자를 붙여서 객체를 생성한다.생성자 함수를 사용해 생성한 객체를 인스턴스라고 합니다.
생성자 함수를 new
연산자와 함께 호출하지 않으면 일반 함수로 동작합니다.
생성자 함수는 프로퍼티 구조가 동일한 인스턴스를 생성하기 위한 클래스처럼 동작합니다.
따라서 생성자 함수가 new
키워드랑 같이 호출되면 다음과 같은 일을 합니다.
function Circle(radius) {
//1. 자바스크립트 엔진이 암묵적으로 빈 객체(인스턴스)를 생성하고 this에 바인딩합니다.
console.log(this); // Circle {}
//2. this에 바인딩 된 인스턴스 초기화
this.radius = radius;
this.getDiameter = function () {
return 2 * this.radius;
};
//3. this에 바인딩된 인스턴스를 암묵적으로 반환
}
🚨바인딩: 식별자과 값을 연결하는 과정(변수 이름과 메모리 공간(주소)를 연결 등)
함수 선언문, 함수 표현식으로 정의한 함수도 생성자 함수로서 호출할 수 있습니다.
생성자 함수로서 호출하는 것은 new
연산자와 함께 호출하여 객체를 생성하는 것을 말합니다.
함수도 객체(일급 객체)이기 때문에 일반 객체가 가지는 내부 슬롯과 내부 메서드를 모두 가지고 있습니다.
하지만 일반 객체와는 다르게 함수는 호출이 가능합니다.
이는 함수 객체만을 위한 [[Environment]], [[FormalParameters]]등의 내부 슬롯과 [[Call]], [[Construct]] 같은 내부 메서드를 추가로 가지고 있기 때문입니다.
함수가 일반 함수로 호출되면 내부 메서드 [[Call]] 호출
생성자 함수로 호출되면 내부 메서드 [[Constructor]]가 호출됩니다.
함수 객체는 호출 가능하니까 전부 [[Call]] 내부 메서드를 가집니다.
하지만 [[Constructor]] 내부 메서드는 생성자 함수로 호출될 수 있는 함수 객체만 가지고 있습니다.
[[Call]]을 가지는 함수 객체를 callable, [[Constructor]]를 가지는 함수 객체를 constructor, 가지지 않는 함수 객체를 non-contructor 라고 합니다.
즉, new
연산자와 함께 호출할 수 있는 함수 객체는 constructor 함수 객체입니다.
non-constructor는 메서드 축약 표현으로 작성한 메서드와, 화살표 함수입니다.
그 외의 함수는 모두 constructor입니다.
ECMAScript 사양에서는 ES6의 메서드 축약 표현으로 작성한 것만 메서드로 인정합니다.
함수 선언문, 함수 표현식으로 정의한 함수를 객체의 메서드로 사용해도 우리는 메서드라고 통칭하지만 실제로 정의한 함수는 일반 함수입니다.
즉, constructor 구별은 함수 정의 방식에 따라 구분합니다.
new
연산자와 함께 함수를 호출하면 생성자 함수로 호출됩니다.
그럼 함수 객체의 [[Call]] 내부 메서드가 호출되는 것이 아니고 [[Constructor]]가 호출되는 것입니다.
생성자 함수를 사용해서 객체를 생성할 때는 반드시 new
키워드를 사용해야 한다고 했습니다.
하지만 개발자도 사람인지라 new
키워드를 사용하지 않고 생성자 함수를 호출하는 실수를 할 때도 있습니다.
함수 본문에서 new.target
은 new
연산자를 사용한 대상 함수 자체를 반환해줍니다.
new
연산자를 사용하지 않고 생성자 함수를 호출했다면 new.target
은 undefined
를 반환합니다.
따라서 다음과 같이 코드를 작성하면 new
키워드를 사용하지 않는 실수를 해도 커버할 수 있습니다.
function User(name) {
if (!new.target) { // new 없이 호출해도
return new User(name); // new를 붙여줍니다.
}
this.name = name;
}
let mingyo = User("민교"); // 'new User'를 쓴 것처럼 바꿔줍니다.
console.log(mingyo.name); // 민교
실수를 커버하는 용도로 코드를 작성했지만 생성자 함수는 new
연산자를 사용해서 호출해야 한다는 규칙은 꼭 지키는 것이 좋습니다.
참고로 자바스크립트에서 제공하는 대부분의 빌트인 생성자 함수는 위 예문처럼 new
연산자로 호출 되었는지 확인합니다.
하지만 String, Number, Boolean
생성자 함수는 new
연산자 없이 호출하면 그냥 문자열, 숫자, 불리언 값을 반환합니다.
생성자 함수에는 보통 retrun
문을 쓰지 않습니다.
암묵적으로 this
에 빈 객체가 할당된 후, 할당한 객체에 프로퍼티들이 추가되고, 이 this
가 다시 암묵적으로 return
되기 때문입니다.
명시적으로 return
문을 사용하는 경우,
return
: this
대신 객체 반환return
: 무시하고 this
반환return
문만 사용: 무시하고 this
반환생성자 함수는 기본적으로 객체 생성을 위한 함수였습니다.
따라서 생성자 함수에서도 메서드를 더할 수 있습니다.
function User(name) {
this.name = name;
this.sayHi = function() {
console.log( "제 이름은 " + this.name + "입니다." );
};
}
let mingyo = new User("정민교");
mingyo.sayHi(); // 제 이름은 정민교입니다.
생성자 함수는 반드시 new
연산자와 함께 호출하여야 합니다.
생성자 함수를 호출하면 내부에서 this
가 암묵적으로 만들어지며, 프로퍼티와 메서드들이 this
에 추가되고, 이 this
를 암묵적으로 return
합니다.
내장 객체 Date
, Map
등을 만들기 위해 자바스크립트에서는 다양항 생성자 함수를 제공합니다.