ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Section 5. 자바스크립트 생성자 함수
    자바스크립트 2023. 3. 29. 18:45

    생성자 함수의 필요성

    const chain1 = {
      name: '판교',
      no: 3,
      introduce () {
        return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
      }
    };
    
    const chain2 = {
      name: '강남',
      no: 17,
      introduce () {
        return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
      }
    };
    
    const chain3 = {
      name: '제주',
      no: 24,
      introduce () {
        return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
      }
    };

    이런식으로 객체들을 계속해서 만들어야 한다면?

    I. 생성자 함수로 객체 만들기

    // 생성자 함수 
    function KangChicken (name, no) {
      this.name = name;
      this.no = no;
      this.introduce = function () {
        return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
      }
    }
    
    // 인스턴스 생성
    const chain1 = new KangChicken('판교', 3);
    const chain2 = new KangChicken('강남', 17);
    const chain3 = new KangChicken('제주', 24);
    
    console.log(chain1, chain1.introduce());
    console.log(chain2, chain2.introduce());
    console.log(chain3, chain3.introduce());
    //KangChicken {name: '판교', no: 3, introduce: ƒ} '안녕하세요, 3호 판교점입니다!'

    하나하나씩 살펴보자.

    관례적으로 함수가 대문자로 시작하면 그건 생성자 함수를 의미한다. 

    함수 안에서 this를 사용하는데 여기서 this가 의미하는 것은 함수로 만들어질 각 객체들 즉, 인스턴스라 한다. 

    chain1~3라는 객체를 생성자 함수를 사용해서 만든다. 이때 new 라는 연산자를 사용하는 것을 볼 수 있다.

    생성했으면 출력을 해보자.

    introduce 함수에 return이 있는데 이때 이 return은 introduce 함수의 return이지 생성자 함수의 return이 아님에 주의하자.

    그렇다면 생성자 함수에는 return문이 없는데 어떻게 작동하는 것일까?

    답은 간단하다. 생성자 함수에서는 암묵적으로 this를 반환하기 때문에 잘 작동이 되는 것이다. 즉, 반환할 this에 name은 무엇이고 no는 무엇인지 정해준다는 것이다. 

     

    정리해보면 다음과 같다.

    • 생성자 함수명은 일반적으로 파스칼 케이스 룰을 따른다.
    • 생성자 함수로 만들어진 객체를 인스턴스 instance라고 부른다.
    • this.~로 생성될 인스턴스의 프로퍼티들을 정의한다.
    • 생성자 함수는 new 연산자와 함께 사용한다.
    • 암묵적으로 this를 반환한다.
    • 생성자 함수에서는 메서드 정의가 불가능하다. (객체 리터럴과 클래스에서는 가능하다).
    function KangChicken (name, no) {
      this.name = name;
      this.no = no;
      this.introduce = function () {
        return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
      }
    }
    
    console.log(KangChicken('홍대', 30)); //undefined

    new를 생략하면 undefined를 반환한다. 이유가 무엇일까?

    생성자 함수와 일반함수는 같은 것으로 만들어져 있는 것이다. 여기에서 new 연산자 여부에 따라서 호출 원리가 다르다는 것을 알고 넘가가자.

     

    new 생략 실수 방지하기

    function KangChicken (name, no) {
      this.name = name;
      this.no = no;
      this.introduce = function () {
        return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
      }
    
      if (!new.target) { // 이 부분이 없다면 chain2는 생성이 되지 않고 undefined 반환됨
        return new KangChicken(name, no);
      }
    }
    
    const chain1 = new KangChicken('판교', 3);
    const chain2 = KangChicken('강남', 17);
    
    console.log(chain1, chain2);
    //KangChicken {name: '판교', no: 3, introduce: ƒ}
    //KangChicken {name: '강남', no: 17, introduce: ƒ}

    new가 없이 사용됐을때는 new를 사용해서 KangChicken(name, no); 을 사용해서 그 결과를 반환해라~ 라는 뜻으로 쓰인다. (재귀함수이다).

    그럼 이렇게 만들어진 인스턴스를 const chain2 = KangChicken('강남', 17); 에서 반환하게 된다.

    II. 생성자 함수로 만들어진 객체

    프로토타입 prototype 이라는 것이 있다. 

    자바스크립트는 처음에 만들어 졌을때 클래스라는 것이 없었다. 대신에 이 prototype이라는 것을 통해서 객체지향 중심의 프로그래밍을 해왔던 것이다. 

    그리고 생성자 함수는 프로토타입과 유기적으로 이어져 있다. 

    function KangChicken (name, no) {
      this.name = name;
      this.no = no;
      this.introduce = function () {
        return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
      }
    }
    
    const chain1 = new KangChicken('판교', 3);
    console.log(chain1);

    위의 예시와 똑같이 chain1이라는 객체를 생성자 함수를 사용해서 만들었다.

    // 본사에서 새 업무를 추가
    // 프로토타입: 본사에서 배포하는 메뉴얼이라고 이해
    KangChicken.prototype.introEng = function () {
      return `Welcome to Kang Chicken at ${this.name}!`;
    };
    
    console.log(chain1.introEng()); //Welcome to Kang Chicken at 판교!
    
    console.log(new KangChicken('강남', 17).introEng()); //Welcome to Kang Chicken at 강남!

    그리고 프로토타입을 사용해서 introEng이라는 새로운 함수(기능)를 추가했다. chain1이 이미 만들어진 상황이라는 점을 명심하자.

    그다음 출력문을 보면 프로토타입을 통한 추가된 함수(기능)가 chain1에 추가된 것을 볼 수 있다. 

    그리고 새롭게 생성된 객체에도 그 기능이 추가된 것을 알 수 있다. 

     

    타 방식으로 만든 객체와의 차이를 한번 살펴보자

    function KangChicken (name, no) {
      this.name = name;
      this.no = no;
      this.introduce = function () {
        return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
      }
    }
    
    function createKangChicken (name, no) {
      return {
        name, no,
        introduce () {
          return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
        }
      }
    }
    
    // 객체 리터럴
    const chain1 = {
      name: '판교', no: 3,
      introduce: function () {
        return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
      }
    };

    생성자 함수를 통해서 객체를 생성하는 방법과 그냥 생으로 객체를 생성했다. 이것들을 비교해보자.

    // 객체 반환 함수
    const chain2 = createKangChicken('강남', 17);
    
    // 생성자 함수
    const chain3 = new KangChicken('제주', 24);
    
    console.log(chain1, chain1 instanceof KangChicken);
    console.log(chain2, chain2 instanceof KangChicken);
    console.log(chain3, chain3 instanceof KangChicken);

    각각의 객체에 대한 출력은 다음과 같다.

    첫번째와 두번째 객체는 그냥 객체의 내용이 뜰 뿐이다. 하지만 세번째는 log상의 기능이긴 하지만 KangChicken이라고 써져있다. 이것으로 인해 chain3는 KangChicken이라는 어떤 무언가로 분류되는 객체 즉, 인스턴스라는 것을 알 수 있다. 

    그리고 instanceof 라는 연산자를 통해 앞에 있는 객체가 KangChicken의 인스턴스인가를 판단해주는 것인데 생성된 객체들이 같은 형태를 띄고 있지만 세번째 객체만 true가 반환된 것을 볼 수 있다. 

     

    생성자 함수 자체의 프로퍼티와 함수

    function KangChicken (name, no) {
      this.name = name;
      this.no = no;
      this.introduce = function () {
        return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
      }
    }
    
    // 본사의 정보와 업무
    KangChicken.brand = '강치킨';
    KangChicken.contact = function () {
      return `${this.brand}입니다. 무엇을 도와드릴까요?`;
    };
    
    const chain1 = new KangChicken('판교', 3);
    
    console.log(KangChicken.contact()); //강치킨입니다. 무엇을 도와드릴까요?
    
    console.log(chain1.contact()); //애러

    예시를 보면 KangChicken이란 생성자 함수에 .연산자를 사용해서 프로퍼티를 추가했다. 함수도 객체기 때문에 .연산자 사용이 가능하다. 그리고 chain1이 아닌 생성자 함수 자체에서 contact() 출력을 하면 출력이 정상적으로 된다. 

    즉, 인스턴스가 아니라 그것을 관리하는 생성자 자체에 기능을 넣고 싶을때 이런식으로도 할 수 있다는 것을 보여주는 예시이다. 

    contact라는 기능을 chain1에 있는지 확인해보니 없는것을 두번째 출력문에서 확인할 수 있다. 

Designed by Tistory.