written by yechoi

[Modern JavaScript Deep Dive] 17장: 생성자 함수에 의한 객체 생성 본문

Born 2 Code/Javascript, Typescript

[Modern JavaScript Deep Dive] 17장: 생성자 함수에 의한 객체 생성

yechoi 2023. 2. 19. 21:39
반응형

17장: 생성자 함수에 의한 객체 생성

생성자 함수: new 연산자와 함께 호출해 객체를 생성하는 함수 (new 없으면 일반 함수로 동작)
인스턴스: 생성자 함수에 의해 생성된 객체

생성자 함수

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

장: 직관적이고 간편
단: 단 하나의 객체만 생성, 여러 개 생성하려면 매번 같은 프로퍼티 기술해야

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

객체(인스턴스)를 생성하기 위한 템플릿(클래스)처럼 생성자 함수를 사용해 프로퍼티 구조가 동일한 객체 여러 개 생성 가능

this

자기 참조 변수. 가리키는 값은 함수 호출 방식에 따라 동적으로 전달.

  • 일반함수: 전여 객체
  • 메서드: 메서드를 호출한 객체
  • 생성자: 생성자 함수가 생성할 인스턴스
function foo() {
    console.log(this);
}
foo(); // window
const obj = { foo };
obj.foo; // obj
const inst = new foo(); //inst

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

인스턴스 생성(필수), 인스턴스 초기화(옵션)

인스턴스 생성 과정

  1. 인스턴스 생성과 this 바인딩
  2. 인스턴스 초기화
  3. 인스턴스 반환
  • 바인딩된 this가 암묵적으로 반환
  • return으로 다른 객체를 명시적으로 반환하면, this가 아닌 return 문에 명시된 객체 반환
  • 명시적으로 원시값을 반환하면, 이는 무시되고 this가 반환
  • => 생성자 함수에서는 return 문을 반드시 생략해야
function Circle(radius) {
    // 1. 암묵적으로 빈 객체가 생성되고 this에 바인딩
    // 2. this에 바인딩되어있는 인스턴스 초기화
    this.radius = radius;
    this.getDiameter = function () {
        return 2 * this.radius;
    }
    // 3. 완성된 인스턴스가 바인딩된 this로 반환
}
// 인스턴스 생성!

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

함수 선언문, 함수 표현식으로 정의한 함수는 생성자로도 호출할 수 있음.
함수는 일반 객체와 달리 호출 할 수 있다.

함수 객체만을 위한 내부 메서드

  • [[Call]]: 일반 함수로서 호출될 때, 이를 가진 함수 객체 callable
  • 모든 함수 객체는 callable
  • [[Constuct]]: 생성자 함수로서 호출될 때, 이를 가진 함수 객체 constructor(<-> non-constructor)
    • 모든 함수가 [[Construct]]를 갖는 건 아님. constuctor일 수 있고, non-constructor 일 수도 있다.

constructor vs non-constructor

  • constructor: 함수 선언문, 함수 표현식, 클래스(클래스도 함수다!!!)
  • non-constructor: 메서드(ES6 메서드 축약 표현을 칭함), 화살표 함수
var obj= {
    // 메서드 축약 표현. 프로퍼티 키를 입력하지 않는다.
    sayHi() {
        console.log('Hi');
    }
}
new obj.sayHi(); // TypeError, 메서드 축약표현은 non-constructor다

new 연산자

new 없이 호출하면 일반 함수로 [[Call]] 호출.
new 함께 호출하면 생성자 함수로 동작, [[Construct]] 호출. (단, 호출하는 함수가 constructor여야 함)

* new 없이 호출했을 때 this는 전역 객체를 가리키기 때문에, 전역 객체의 프로퍼티와 메서드를 생성하는 효과가 날 수도 (예제 17-18)
=> 생성자는 파스칼 케이스(첫 문자 대문자)로 명명해, 일반 함수와 구별해야

new.target

  • 모든 함수 내부에서 암묵적인 지역 변수와 같이 사용, 메타 프로퍼티라고 부름
  • new 연산자와 함께 생성자로 호출됐는지 확인할 수 있음
    • 생성자 함수로 호출 된 경우: new.target은 함수 자신
    • 일반 함수로 호출된 경우: new.target은 undefined
function Circle(radius) {
    // 이 함수가 new와 함꼐 호출된 것이 아니라면
    if (!new.target) {
        // 직접 재귀 호출로 인스턴스를 생성해 반환한다
        return new Circle(radius);
    }
    ...
}

스코프 세이프 생성자 패턴

new.target은 ES6에서 도입된 최신 문법. new.target을 사용할 수 없다면 스코프 세이프 생성자 패턴을 사용하자.

function Circle(radius) {
    if (!(this instance of Circle)) {
        return new Circle(radius);
    }
    ...
}

빌트인 생성자 함수는 new 연산자와 함께 호출되었는지 확인한 후 적절한 값 반환

  • Object와 Function 생성자 함수는 new 없이 호출해도 new 연산자와 함께 호출했을 떄와 동일하게 동작
  • String, Number, Boolean 생성자 함수는 new 없이 호출하면 객체가 아닌 문자열, 숫자, 불리언 값을 반환 -> 타입 변환으로 쓸 수 있음.
반응형