nhyunzi
[모던 자바스크립트 Deep Dive] 17 생성자 함수에 의한 객체 생성 본문
17.1 Object 생성자 함수
생성자 함수란 new 연산자와 함께 호출되어 인스턴스를 생성하는 함수를 말한다. new 연산자와 함께 Objcet 생성자 함수를 호출하며 객체를 생성해 반환한다.
만약 new 연산자를 함께 호출하지 않으면 일반 함수로 동작한다.
// 빈 객체 생성
const person = new Object();
person.name = 'Ahn';
person.sayHello = function(){
console.log('Hi! My name is '+this.name);
// Object 말고도 String, Number, Boolean, Function, Array, Date, RegExp, Promise 등의 빌트인 생성자 함수 제공
//타입은 전부 object
const strObj = new String('Ahn'); // String {"Ahn"}
const numObj = new Number(123); //Number {123}
const boolObj = new Boolean(true);// Boolean {true}
const func = new Function('x','return x*x'); // f anonymous(x)
const arr = new Array(1,2,3); //[1,2,3]
const regExp = new RegExp(/ab+c/i);// /ab+c/i
const date = new Date(); //Thu June 20 2023:08:36:33 GTM+0900 (대한민국 표준시)
17.2 생성자 함수
객체 리터럴 생성 방식은 직관적이고 간편하지만 단 하나의 객체만 생성하기 때문에 동일한 프로퍼티를 가지는 객체더라도 매번 같은 프로퍼티를 기술해야해서 비효율적이다.
const circle1 = {
radius : 5,
getDiameter(){
return 2*this.radius;
}
};
console.log(circle1.getDiameter()))//10
const circle2 = {
radius : 10,
getDiameter(){
return 2*this.radius;
}
};
console.log(circle2.getDiameter()))//20
생성자 함수를 이용해 객체를 생성하게 되면 생성자 함수를 인스턴스를 생성하기 위한 템플릿처럼 사용할 수 있기 때문에 같은 구조의 객체를 간편하게 여러개 생성할 수 있다.
fucntion Circle(radius){
this.radius : radius;
this.getDiameter = function(){
return 2*this.radius;
}
}
const circle1 = new Circle(5);
const circle1 = new Circle(10);
console.log(circle1.getDiameter()); //10
console.log(circle2.getDiameter()); //20
생성자 함수에서 따로 인스턴스를 생성하고 반환하는 코드는 존재하지 않는데 이는 자바스크립트 엔진에서 암묵적인 처리를 통해 처리하기 때문이다.
런타임 이전에 new를 통해 생성된 인스턴스가 this에 바인딩 된다. 생성자 함수 안의 코드가 한줄씩 실행되며 인스턴스를 초기화한다.위의 처리가 끝나게 되면 완성된 인스턴스가 바인딩 된 this가 암묵적으로 반환된다.
만약 this가 아닌 다른 객체를 명시적으로 반환하게 되면 return문에 명시한 객체가 반환된다.
(단, 원시값을 반환하게 되면 무시되며 암묵적으로 this가 반환된다.)그렇기 때문에 생성자 함수 내부에서는 return 문을 반드시 생략하도록 한다.
내부 메서드 [[Call]]과 [[Construct]]
함수도 객체이기 때문에 함수 선언문 또는 함수 표현식은 생성자 함수로도 호출이 가능한다.
이는 함수 객체가 일반 객체가 가지고 있는 내부 슬롯과 내부 메서드를 전부 가지고있기 때문인데 함수 객체는 일반 객체와는 또 다른 특징을 가지고 있다. 함수는 호출할 수 있다.
함수가 일반 함수로 호출되면 [[Call]]이 호출 되고(callable) new 연산자와 함께 생성자 함수로 호출되면 [[Construct]]가 호출된다(constructor).
하지만 모든 함수는 callable이지만 [[Construct]]를 갖지 않은 non-constructor일 수도 있다.
자바스크립트 엔진은 함수 정의 방식에 따라 constructor와 non-constructor로 구분한다.
주의해야할 점은 ECMAScript 사양에서 메서드로 인정하는 범위가 일반적인 메서드보다 좁다는 것이다.
function foo(){}
const bar = function(){};
const baz = {
x : function(){} //일반 함수로 정의되었기 때문에 메서드로 인정되지 않는다.
}
const arrow = () => {};
const obj = {
x(){} // 메서드 축약 표현을 사용했으므로 메서드로 인정
}
new foo(); //->foo {}
new bar(); //->bar {}
new baz.x(); //->x {}
new arrow(); // TypeError :arrow is not a constructor
new obj.x(); // TypeError :obj.x is not a constructor
new.target
생성자 함수는 일반 함수와 구분해서 사용하기 위해 파스칼 케이스로 명명하여 일반 함수와 구별할 수 있도록 노력하는데, 실수는 언제나 발생이 가능하다.
그렇기 때문에 ES6에서 new 연산자와 함께 생성자 함수로 호출되었는지 확인할 수 있는 new.target을 지원한다.(일반 함수에서 호출된 new.target은 undefined이다.) 인터넷 익스플로러에서는 new.target을 지원하지 않기 때문에 대신 instanceof를 사용할 수 있다.