Object 생성자 함수
•
new 연산자와 함께 호출하여 객체를 생성하는 함수
생성자 함수 = new + function
const person = new Object();
JavaScript
복사
•
인스턴스(instance) : 이때 생성된 객체 (person이 인스턴스)
•
Object 외에도 String, Number, Boolean 등의 생성자 함수 제공
생성자 함수
객체 생성(빌트인) 생성자
객체 리터럴에 의한 객체 생성 방식의 문제점
•
동일한 프로퍼티를 갖는 객체를 여러 개 생성해야하는 경우 매번 같은 프로퍼티 기술 필요
ex) circle이라는 객체 여러개
생성자 함수에 의한 객체 생성 방식의 장점
•
객체를 생성하기 위한 템플릿(클래스)처럼 생성자 함수를 사용하여 프로퍼티 구조가 동일한 객체 여러 개를 간편하게 생성 가능 (원본에 대한 복사본 생성 느낌)
ex) circle이라는 객체 한개
객체 여러개를 객체 리터럴로 정의할 때보다 간편하게 생성 가능
(함수 하나만 정의해 놓고 new연산자와 같이 생성자 함수로 객체 생성)
•
생성자 함수는 일반 함수와 동일한 방법으로 생성자 함수를 정의하고 new 연산자와 함께 호출하면 생성자 함수로 동작
•
new연산자 같이 안쓰면 생성자 함수가 아닌 일반 함수로 동작
this
•
this : 자기 참조 변수
•
this가 가리키는 값 바인딩은 함수 호출 방식에 따라 동적으로 결정
함수 호출 방식 | this가 가리키는 값(this 바인딩) |
일반함수 | 전역 객체 |
메서드 | 메서드를 호출한 객체 |
생성자 함수 | 생성자 함수가 생성할 인스턴스 |
인스턴스 : 일반적으로 실행 중인 임의의 프로세스, 클래스의 현재 생성된 “객체”
// 함수는 다양한 방식으로 호출될 수 있다.
function foo() {
console.log(this);
}
// 일반적인 함수로서 호출
// 전역 객체는 브라우저 환경에서 window, Node.js 환경에서 global
foo(); // window
// 메서드로서 호출
const obj = { foo }; // ES6 프로퍼티 축약 표현
obj.foo(); // {foo: ƒ}
// 생성자 함수로서 호출
const inst = new foo(); // foo {}
JavaScript
복사
생성자 함수의 인스턴스 생성 과정
•
생성자 함수의 역할: 인스턴스를 생성하기 위한 템플릿(클래스)으로서 동작
인스턴스 생성, 생성된 인스턴스를 초기화(인스턴스 프로퍼티 추가 및 초기값 할당)
•
함수 내부에 인스턴스 생성및 반환하는 코드가 없어도 JS엔진은 암묵적인 처리를 통해 인스턴스를 생성하고 반환.
1.
인스턴스 생성과 this 바인딩 (런타임 이전에 암묵적으로 빈 객체 생성, 이 빈 객체는 인스턴스이고 this에 바인딩)
바인딩 --> 변수 이름(식별자)와 값을 연결하는 과정 (this라는 식별자)
2.
인스턴스 초기화 (런타임에 코드가 한줄 씩 실행되어 this에 바인딩 되어 있는 인스턴스(객체) 초기화)
3.
인스턴스 반환 (완성된 인스턴스가 바인딩된 this를 암묵적으로 반환)
function Circle(radius) {
// 1. 암묵적으로 인스턴스가 생성되고 this에 바인딩
console.log(this); // Circle {}
// 2. this에 바인딩되어 있는 인스턴스를 초기화
this.radius = radius;
this.getDiameter = function () {
return 2 * this.radius;
};
// 3. 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환
// return {}; // 명시적 반환 - 동작 훼손
}
// 인스턴스 생성. Circle 생성자 함수는 암묵적으로 this를 반환
const circle = new Circle(1);
console.log(circle); // Circle {radius: 1, getDiameter: ƒ}
JavaScript
복사
3번의 과정에서 만약 다른 객체를 명시적으로 반환하면 this가 반환되지 못하고 명시한 객체가 반환되고, 원시값 반환 시 암묵적으로 this가 반환
생성자 함수 내부에선 return문을 반드시 생략 ⇒ 생성자 내부 함수의 기본 동작 훼손 가능성 X
내부 메서드 [[Call]]과 [[Construct]]
•
함수 선언문 또는 함수 표현식으로 정의한 함수는 생성자 함수로서 호출 가능
( = new와 같이 호출하여 객체 생성한다는 말)
•
함수는 객체이므로 일반 객체와 같이 동일하게 동작 BUT
유일한 차이점 : 일반객체는 호출 불가능, 함수는 호출 가능
// 함수는 객체다.
function foo() {}
// 함수는 객체이므로 프로퍼티를 소유할 수 있다.
foo.prop = 10;
// 함수는 객체이므로 메서드를 소유할 수 있다.
foo.method = function () {
console.log(this.prop);
};
foo.method(); // 10
JavaScript
복사
•
함수 호출 시: 함수 객체의 내부 메서드 [[Call]]이 호출 --> 이것을 가지고 있는 함수 객체는 callable
•
생성자 함수 호출 시: 내부 메서드 [[Construct]]가 호출
--> 내부 메서드를 가지고 있는 함수 객체 : constructor,
--> 내부 메서드를 가지고 있지 않은 함수 객체 : non-constructor
•
모든 함수 객체는 callable이지만 constructor일 수도 있고 non-constructor일 수도 있다.
constructor와 non-construcor 구분
•
constructor: 함수 선언문, 함수 표현식, 클래스
•
non-constructor: 메서드(ES6 메서드 축약 표현), 화살표 함수
•
non-constructor인 메서드 및 함수는 new연산자와 같이 사용하였을 시, TypeError발생
•
객체의 메서드로 정의할 시, 메서드 축약표현이 아닌 함수형식(x: function() {})으로 정의한 것들은 일반 함수로 정의되어 constructor이다.
•
ECMAScript 사양에서 메서드란 ES6의 메서드 축약 표현 만을 의미한다.
new 연산자
•
new 연산자와 함께 함수를 호출하게 되면 내부 메서드 [[Call]이 호출 되는 것이 아니라 [[Construct]]가 호출된다. 단 이 경우 함수는 non-constructor가 아닌 constructor이어야 한다.
생성자 함수는 파스칼 케이스(PascalCase)로 명명하여 일반 함수(basicFuction)와 구별할 수 있도록
new.target
•
파스칼 케이스(PascalCase)로 해도 실수할 경우를 대비한 메타 프로퍼티.
•
this와 유사 : constructor인 모든 함수 내부에서 암묵적 지역변수와 같이 사용된다.
•
new 연산자와 함께 생성자 함수로서 호출되면 함수 내부의 new.target은 함수 자신을 가리킨다. new 연산자 없이 일반함수로서 호출된 함수 내부의 new.target은 undefined다.
function Circle(radius) {
// new 연산자와 함께 호출되지 않았다면 new.target은 undefined
if (!new.target) {
// new 연산자와 함께 생성자 함수를 재귀 호출하여 생성된 인스턴스 반환
return new Circle(radius);
}
}
JavaScript
복사
•
ES6에서 도입되어 IE는 지원하지 않아서 아래의 스코프 세이프 생성자 패턴을 사용하기도 함.
스코프 세이프 생성자 패턴
if (!(this instanceof Circle)) { return new Circle(radius); }
JavaScript
복사