JS 생성자 함수에 의한 객체 생성

생성자(constructor) 함수new 연산자와 함께 호출하여 인스턴스 객체를 생성하는 함수 를 말한다. 생성자 함수에 의해 생성된 객체를 인스턴스(instance)라 한다.

Object 생성자 함수

new 연산자와 함께 Object 생성자 함수를 호출하면 빈 객체를 생성 후 반환. 이후에 프로퍼티나 메소드를 추가할 수 있다. Object 생성자 함수 방식은 특별한 이유가 없다면 그다지 유용하지 않음.

자바스크립트가 제공하는 빌트인 생성자 함수
String, Number, Boolean, Function, Array, Date, RegExp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// String 생성자 함수에 의한 String 객체 생성
const strObj = new String('Lee');
console.log(typeof strObj); // object
console.log(strObj); // String {"Lee"}

// Number 생성자 함수에 의한 Number 객체 생성
const numObj = new Number(123);
console.log(typeof numObj); // object
console.log(numObj); // Number {123}

// Boolean 생성자 함수에 의한 Boolean 객체 생성
const boolObj= new Boolean(true);
console.log(typeof boolObj); // object
console.log(boolObj); // Boolean {true}

생성자 함수

객체 리터럴에 의한 객체 생성 방식의 문제점

직관적이고 간편하지만 단 하나만의 객체를 생성한다. 똑같은 프로퍼티를 가지는 객체가 여러개 필요할 경우, 매번 같은 프로퍼티를 기술해야 한다. (메소드의 값이 동일한 경우가 일반적)

생성자 함수에 의한 객체 생성 방식의 장점

객체를 생성하기 위한 템플릿처럼 생성자 함수를 사용할 수 있다. 즉, 프로퍼티 구조가 동일한 객체 여러개를 간단하게 생성할 수 있다.

  • 일반 함수와 동일한 방법으로 생성자 함수를 정의 하고 new 연산자와 함께 호출 하면 해당 함수는 생성자 함수로 동작한다.
  • new 연산자와 함께 생성자 함수를 호출하지 않으면 생성자 함수가 아니라 일반 함수로 동작한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Circle(radius) {
this.radius = radius;
this.getDiameter = function () {
return 2 * this.radius;
};
}

const circle1 = new Circle(2);
// 반지름이 2인 Circle 객체를 생성
const circle2 = new Circle(4);
// 반지름이 4인 Circle 객체를 생성

console.log(circle1.getDiameter()); // 4
console.log(circle2.getDiameter()); // 8

this
this가 가리키는 값, 즉 this 바인딩은 함수 호출 방식에 따라 동적으로 결정된다.

내부 메소드 [[Call]]과 [[Construct]]

  • 함수가 일반적인 함수로 호출되면 [[Call]] 호출 되고, new(또는 super) 연산자와 함께 생성자 함수로서 호출되면 [[Construct]]가 호출 된다.
  • 모든 함수 객체는 내부 메소드 [[Call]]을 가지고 있기 때문에 호출할 수 있다.
  • 모든 함수 객체가 [[Construct]]를 갖지는 않는다.
모든 함수 객체는 callable이지만 모든 함수 객체가 constructor인 것은 아니다.

callable: 내부 메소드 [[Call]]을 갖는 함수 객체

constructor: 내부 메소드 [[Construct]]를 갖는 함수 객체
non-constructor: 내부 메소드 [[Construct]]를 갖지 않는 함수 객체

super 키워드
ES6에서 도입된 클래스에서 부모 클래스를 참조할 때나 부모 클래스의 생성자를 호출할 때 사용된다.

constructor와 non-constructor의 구분

자바스크립트 엔진은 함수를 생성할 때 FunctionCreate라는 추상연산(abstract operation)을 사용 한다. 추상 연산 FunctionCreate는 함수 정의가 평가될 때 호출된다. 이때 함수 정의 방식에 따라 FunctionCreate의 첫번째 매개변수 kind에 함수의 종류를 나타내는 문자열이 전달 된다.

구분 함수의 종류를 나타내는 문자열
일반 함수 정의(함수 선언문, 함수 표현식)을 평가할 때 Normal
화살표 함수 정의를 평가할 때 Arrow
메소드 정의를 평가할 때 Method

추상연산(abstract operation) : ECMAScript 사양에서 내부 동작의 구현 알고리즘을 표현한 것.

ECMAScript 사양에서 “메소드 정의”로 인정하는 범위가 일반적인 메소드보다 좁다. ES6의 메소드 축약표현만을 메소드 정의로 인정 한다.

  • 일반 함수 로 정의된 함수만이 constructor
  • 함수의 종류가 Arrow, Method 인 함수는 non-constructor

생성자 함수의 인스턴스 생성 과정

  1. 인스턴스 생성과 this 바인딩
  2. 인스턴스 초기화
  3. 인스턴스 반환

new 연산자

new 연산자와 함께 constructor 함수를 호출하면 해당 함수는 생성자 함수로 동작한다. new 없이 생성자 함수를 호출하면 일반 함수([[Construct]]가 아닌 [[Call]])이 호출된다. 일반 함수와 생성자 함수의 차이를 위해서 생성자 함수는 일반적으로 파스칼 케이스로 명명 한다.

new.target

  • 메타 프로퍼티(Meta Property)라고 부른다.
  • new 연산자 없이 생성자 함수를 호출하는 것을 방지하기 위해 new.target을 지원한다.
  • this와 유사하게 모든 함수 내부에서 암묵적인 지역변수와 같이 사용된다.
  • 함수 내부에서 new.target을 사용하면 new 연산자와 함께 호출되었는지 확인 가능.
    • new 연산자와 함께 호출되면 함수 내부의 new.target은 함수 자신을 가리킨다.
    • new 연산자 없이 호출된 함수 내부의 new.targetundefined이다.
  • IE는 new.target을 지원하지 않는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Circle(radius) {
// 이 함수가 new 연산자와 함께 호출되지 않았다면 new.target은 undefined이다.
if (!new.target) {
// new 연산자와 함께 호출하여 생성된 인스턴스를 반환한다.
return new Circle(radius);
}

this.radius = radius;
this.getDiameter = function () {
return 2 * this.radius;
};
}

const circle = Circle(5);
console.log(circle.getDiameter());

스코프 세이프 생성자 패턴

  • IE같이 new.target을 사용할 수 없는 상황이라면 스코프 세이프 생성자(Scope-Safe Constructor) 패턴을 사용할 수 있다.
  • new 연산자와 함께 생성자 함수에 의해 생성된 객체(인스턴스)는 프로토타입에 의해 생서자 함수와 연결된다. 이를 이용해 new 연산자와 함께 호출되었는지 확인할 수 있다.
  • 대부분의 빌트인 생성자 함수는 new 연산자와 함께 호출되었는지를 확인한 후 적절한 값을 반환한다.
    • Object / Function 생성자 함수는 new 연산자 없이 호출해도 new 연산자와 함께 호출했을 때와 동일하게 동작
    • String 생성자 함수는 new 연산자와 함께 호출했을 때 String 객체를 생성하여 반환하지만 new 연산자 없이 호출하면 문자열 리터럴을 반환
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Circle(radius) {
// 이 함수가 new 연산자와 함께 호출되지 않았다면
// 이 시점의 this는 전역 객체 window를 가리킨다.
if (!(this instanceof Circle)) {
return new Circle(radius);
}

this.radius = radius;
this.getDiameter = function () {
return 2 * this.radius;
};
}

// new 연산자 없이 생성자 함수를 호출하여도 생성자 함수로서 호출된다.
const circle = Circle(5);
console.log(circle.getDiameter()); // 10

REFERENCE
https://poiemaweb.com

  • © 2020-2025 404 Not Found
  • Powered by Hexo Theme Ayer