04. 생성자 함수

📌 4-1 생성자 함수란?

ES6 문법 이전에 함수를 클래스형태로 사용할 수 있는 함수이다.

💡 new 연산자를 사용하여 클래스처럼 객체를 생성한다. (인스턴스 생성)
💡 this를 사용하여 외부에서 접근할 수 있도록 한다.
💡 var, let, const 사용하여 변수를 생성하면 생성자함수 안에서만 연산이 된다.
💡 Class Naming 처럼 파스칼 표기법을 사용하여 구별할 수 있도록 한다.

📌 4-2 생성자 함수를 사용이유

인스턴스를 생성하는 클래스처럼 객체를 효율적으로 생성할 수 있다.

// 좌항 피연산자가 10 우항 피연산자가 2 더하기 연산을 수행하는 add()를 포함하는 Obj생성
const sum1 = {
    num1 : 10,
    num2 : 2,
    add() {
        return this.num1 + this.num2;
    }
}
// 좌항 피연산자가 10 우항 피연산자가 10 더하기 연산을 수행하는 add()를 포함하는 Obj생성
const sum2 = {
    num1 : 10,
    num2 : 10,
    add() {
        return this.num1 + this.num2;
    }
}
console.log(sum1.add()); // 12 출력
console.log(sum2.add()); // 20 출력

객체리터럴로 생성하면 다른 결과값을 얻기 위해서 계속 동일한 프로퍼티를 갖는 객체를 여러개 생성한다.

// 생성자 함수를 이용한 Obj 생성
function Sum(num1, num2) {
    this.num1 = num1;
    this.num2 = num2;
    this.add = function() {
        return this.num1 + this.num2;
    }
}
// 인스턴스 sum1 생성
const sum1 = new Sum(10, 2);
// 인스턴스 sum2 생성
const sum2 = new Sum(10, 10);
console.log(sum1.add()); // 12 출력
console.log(sum2.add()); // 20 출력

이와 같이 효율적으로 다른 결과값의 객체를 생성할 수 있다.

📌 4-3 생성자 함수의 외부접근 내부접근

  1. 생성자 함수를 이용하면 외부접근이 가능한 변수 this와 외부접근이 불가능한 변수를 만들수 있다.

  2. var를 사용하여도 함수 레벨 스코프이기 때문에 외부로 전역변수화가 일어나진 않지만 내부에서는 일어나기 때문에 const와 let을 사용한다.

function Sum(num1, num2) {
    this.num1 = num1;
    this.num2 = num2;
    const numPrivate = 2;
    this.add = function() {
        return this.num1 + this.num2 - numPrivate;
    }
}
// 인스턴스 생성
const sum1 = new Sum(10, 2);
// 외부에서 접근 가능
console.log(sum1.num1); // 10 출력
console.log(sum1.numPrivate); // undefined 출력
console.log(sum1.add()); // 10 출력

이와 같이 내부에서만 사용가능한 변수와 외부에서 접근 가능한 변수를 생성한다.

📌 4-4 생성자 함수의 생성조건

생성자 함수로 인스턴스를 생성할려면 일반 함수로 정의된 함수만 가능하다.

// 함수 선언문
function Sum(num1, num2) {
    this.num1 = num1;
    this.num2 = num2;
    this.add = () => {
        return this.num1 + this.num2;
    }
}
// 함수 표현식
const FunSum = function (num1, num2) {
    this.num1 = num1;
    this.num2 = num2;
    this.add = () => {
        return this.num1 + this.num2;
    }
}
// 화살표 함수 정의식
const ArrowSum = (num1, num2) => {
    this.num1 = num1;
    this.num2 = num2;
    this.add = () => {
        return this.num1 + this.num2;
    }
}
// 각각 인스턴스 생성
const sum1 = new Sum(10, 2);
const sum2 = new FunSum(10, 2); 
const sum3 = new ArrowSum(10, 2);
console.log(sum1.add()); // 12 출력
console.log(sum2.add()); // 12 출력
console.log(sum3.add()); // 오류 출력
👉 'ArrowSum is not a constructor' (오류)

이유는 함수를 생성할 때 가지고 있는 내부 메서드에 의한 현상이다.
1. 일반 함수로 호출을 하면 내부메서드 [[Call]]이 호출된다.
2. new 연산자와 생성자 함수가 호출이 되면 내부 메서드 [[Construct]]가 호출되기 때문이다.

💡 그러므로 생성자 함수 안에서 사용한 화살표 함수는 메서드로는 사용이 가능하지만 생성자 함수로는 사용이 불가능하다.

📌 4-5 Callable, Constructor

함수 표현식의 prototype과 화살표 함수 정의식의 prototype을 확인해보면 생성자 함수로 사용할 수 없는 이유를 확인이 가능하다.

const generalFunction = function () {} // 함수 표현식
const arrowFunction = () => {} // ES6 화살표 함수 정의식
console.log(generalFunction.prototype); // 이미지 참고
console.log(arrowFunction.prototype); // undefined 출력

👀 generalFunction의 프로토타입에 constructor의 메서드로 인해 생성자함수로 호출이 가능하다.

📌 4-6 생성자 함수의 this

this가 가르키는 객체는 크게 3가지로 바인딩 된다.

1. 함수호출 this -> 전역 객체
2. 객체 메서드로서 호출 -> 메서드 호출 객체
3. 생성자 함수로서 호출 -> 생성한 인스턴스 객체

// 함수 생성
function generalFunction(num1, num2) {
    console.log(this);
    return num1 + num2;
}
// 객체 생성
const object = {
    num1 : 10,
    num2 : 10,
    add : function() {
        console.log(this);
        return this.num1 + this.num2;
    }
}
// 생성자 함수 생성
function ConstructorFunction(num1, num2) {
    this.num1 = num1;
    this.num2 = num2;
    this.add = () => {
        console.log(this);
        return this.num1 + this.num2;
    }
}
// sum1에 함수호출값 저장
const sum1 = generalFunction(10, 10);	
// sum2에 오브젝트 저장
const sum2 = object;
// sum3, sum4에 인스턴스 생성
const sum3 = new ConstructorFunction(10, 10);
const sum4 = new ConstructorFunction(10, 10);
// this가 인스턴스를 가르키는지 확인하기 위해서 sum5에 obj 저장
const sum5 = object;
// obj안에 있는 num1에 20 재할당
sum2.num1 = 20;
// 인스턴스 객체 sum4에 this.num1 = 20 재할당
sum4.num1 = 20;
console.log(sum1); // 20 출력 전역객체 this
console.log(sum2.add()); // 30 출력 객체 Obj 가르키는 this 출력
console.log(sum3.add()); // 20 출력 새롭게 생성된 인스턴스를 가르키는 this 출력
console.log(sum4.add()); // 30 출력 새롭게 정의된 인스턴스를 가르키는 this 출력
console.log(sum5.add()); // 30 출력 객체 obj 가르키는 this 출력

📃 4-6 설명

  1. 객체와 배열은 원시값이 아니므로 변수에 값이 저장되는 것이 아닌 배열과 객체를 가리키는 주소값이 저장된다고 생각하면 이해가 빠르다.
  2. sum2.num1를 20으로 바꾸면 sum5도 obj 주소값이 저장되어 있으므로 sum5의 출력값도 obj의 값이 변했으므로 바뀌게 되는것이다.
  3. sum4.num1를 20으로 바꾸더라도 인스턴스는 새롭게 생긴 객체이기 때문에 sum3과 sum4는 주소값을 다르게 가지는 객체 2개가 생성이 된다. 그래서 결과값도 바뀌지 않는다.

📌 4-7 생성자 함수의 결과값 반환

생성자 함수의 결과값은 this 객체이다.

// 생성자 함수 생성
function ConstructorFunction(num1, num2) {
    // 1. 빈 객체를 생성하고 this를 바인딩한다. (빈 객체 생성)
    // 2. this에 바인딩 값을 초기화 하고 생성자 함수가 받은 초기값을 할당한다.
    this.num1 = num1;
    this.num2 = num2;
    this.add = () => {
        return this.num1 + this.num2;
    }
    /* 3. 생성자 함수의 실행문이 종료되면 암묵적으로 생성자 함수가 받은 초기값으로 
    바인딩된 this를 반환한다. */
    // 명시적으로 return 값을 원시값으로 지정한다.
    return 0;
}
const sum = new ConstructorFunction(10, 10);
console.log(sum);

// 생성자 함수 생성
function ConstructorFunction(num1, num2) {
    this.num1 = num1;
    this.num2 = num2;
    this.add = () => {
        return this.num1 + this.num2;
    }
    // 명시적으로 return 값을 객체로 지정한다. (함수도 객체이다.)
    return {}; // function () {} 바꾸면 함수가 출력된다.
}
const sum = new ConstructorFunction(10, 10);
console.log(sum);

function ConstructorFunction(num1, num2) {
    this.num1 = num1;
    this.num2 = num2;
    this.add = () => {
        return this.num1 + this.num2;
    }
    // 명시적으로 return 값을 this로 지정
    return this;
}
const sum = new ConstructorFunction(10, 10);
console.log(sum);

💡 생성자 함수는 생성된 인스턴스의 this 객체를 return 한다.

📌 4-8 생성자 함수 메서드를 prototype으로 생성하기

졸업작품 프로젝트를 하다가 본 템플릿 모듈에서는 생성자 함수 메서드를 prototype으로 생성하고 있었다. 이것도 깔끔해보여서 졸업작품 프로젝트에서는 모듈을 만들 때 이렇게 사용했었다.

function ConstructorFunction(num1, num2) {
    this.num1 = num1;
    this.num2 = num2;
}
ConstructorFunction.prototype.add = function() {
    return this.num1 + this.num2;
}
const sum = new ConstructorFunction(10, 10);
console.log(sum.add()); // 20 출력

👉 bind(), call(), apply(), ES6 new.target 등등 생성자 함수의 개념들이 아직 많은것 같다... 너무 길어질꺼 같아서 다음에 다시 정리해 봐야겠다.

좋은 웹페이지 즐겨찾기