생성자 함수에 의한 객체 생성 (Constructor)

Posted by Seongkyun Yu on 2020-03-01
Estimated Reading Time 2 Minutes
Words 470 In Total
Viewed Times

Object 생성자 함수

new Object(); 를 통해 빈 객체를 생성하고 생성된 객체에 프로퍼티와 메소드를 추가하여 사용한다.


생성자 함수

  • C++, Java처럼 프로퍼티 구조가 동일한 객체를 간편하게 생성할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 생성자 함수
    function Discount(price) {
    // 생성자 함수 내부의 this는 생성자 함수가 생성할 인스턴스를 가리킨다.
    this.price = price;
    this.getDiscountPrice = function () {
    return 0.9 * this.price;
    };
    }

    // 인스턴스의 생성
    const dprice1 = new Discount(5000); // 할인전 가격이 5000원인 객체를 생성
    const dprice2 = new Discount(10000); // 할인전 가격이 10000원인 객체를 생성

    new 연산자와 함께 호출하면 해당 함수는 생성자 함수로 동작한다.


  • 함수는 객체이므로 일반 객체와 동일하게 동작한다.
    함수로서 동작하기 위해 내부 슬롯과 내부 메소드를 추가로 가지고 있다.

    내부 메소드:
    [[Call]]: callable, 호출할 수 있는 객체 (함수)
    [[Construct]]: constructor, 생성자 함수로서 호출할 수 있는 객체 (new)

    모든 함수는 callable하지만, 모두가 constructor는 아니다.


  • Constructor로 인정 받기 위해선 일반 함수 정의로 선언돼야 한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 일반 함수 정의 (constructor)
    function Normal() {};
    const NormalLiteral = function () {};
    const NormalObjFunc = {
    x: function () {} // 이렇게 선언되면 메소드가 아니라 일반 함수이다
    }

    new Normal(); // OK
    new NormalLiteral(); // OK
    new NormalObjFunc.x(); // OK

    위 예시 이외에 arrow함수나 축약 표현으로 생성된 메소드는 생성자를 갖지 못한다.
    이를 구별하기 위해 생성자 함수는 첫문자를 대문자로 쓰는 파스칼 케이스로 명명한다.


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

    인스턴스(빈 객체)와 this 바인딩 -> 인스턴스 초기화 -> 인스턴스가 바인딩된 this 반환

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function Discount(price) {
    // 1. 암묵적으로 인스턴스가 생성되고 this에 바인딩된다.

    // 2. this에 바인딩되어 있는 인스턴스를 초기화한다.
    this.price = price;
    this.getDiscountPrice = function () {
    return 0.9 * this.price;
    };

    // 3. 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환된다.
    }

    // 인스턴스 생성. Circle 생성자 함수는 암묵적으로 this를 반환한다.
    const dprice1 = new Discount(5000);



  • new 연산자

    constructor 함수와 함께 사용되면 생성자 함수로 작동한다. 형식상 차이는 없다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function Discount(price) {
    this.price = price;
    this.getDiscountPrice = function () {
    return 0.9 * this.price;
    };
    }

    const dprice1 = Discount(5000);
    console.log(dprice1); // undefined



  • new.target

    함수 내부에서 new.target를 사용하면 new 연산자와 함께 함수가 호출되었는지 확인할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function Discount(price) {
    if (!new.target) {
    // new 연산자와 함께 호출하여 생성된 인스턴스를 반환한다.
    return new Discount(radius);
    }

    this.price = price;
    this.getDiscountPrice = function () {
    return 0.9 * this.price;
    };
    }

    const dprice = Discount(5000);

    ES6 이전에는 스코프 세이프 생성자 패턴을 이용해야 한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // Scope-Safe Constructor Pattern
    function Discount(price) {
    // 생성자 함수가 new 연산자와 함께 호출되면 함수의 선두에서 빈 객체를 생성하고
    // this에 바인딩한다. 이때 this와 Discount는 프로토타입에 의해 연결된다.

    // 이 함수가 new 연산자와 함께 호출되지 않았다면 이 시점의 this는 전역 객체 window를 가리킨다.
    // 즉, this와 Discount는 프로토타입에 의해 연결되지 않는다.
    if (!(this instanceof Discount)) {
    // new 연산자와 함께 호출하여 생성된 인스턴스를 반환한다.
    return new Discount(radius);
    }

    this.price = price;
    this.getDiscountPrice = function () {
    return 0.9 * this.price;
    };
    }

    const dprice = Discount(5000);

참고자료: poiemaweb.com


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !