JavaScript/Vanilla JS

객체 Object - 5 [생성자 함수] (프로토타입, new키워드)

유혁스쿨 2022. 1. 23. 23:05
728x90
반응형

생성자 함수

new 키워드로 객체를 생성할 수 있는 함수를 의미한다.

이전 포스팅에서 함수로 객체를 생성하는 코드를 구현해보았지만 new 키워드를 사용하지 않았으므로 생성자 함수라고 부를 수 없다.

 

아래 코드는 Student 생성자 함수를 만드는 코드이다.

function Student () {

}

생성자 함수의 이름은 일반적으로 대문자로 시작한다.

대문자로 시작하지 않아도 문제 없지만 대부분의 개발자가 지키는 관례 같은 규칙이므로 대문자로 선언한다.

기본적으로 자바스크립트 내부의 생성자 함수들 또한 모두 대문자로 시작하도록 구현되어 있다.

 

위와같이 생성한 생성자 함수는 아래 코드와 같이 new 키워드로 객체를 생성한다.

function Student () {

}
var student = new Student();

 

생성자 함수 안에서는 this 키워드로 생성자 함수로 생성될 객체의 속성을 지정한다.

(여기서 this는 생성된 객체 식별자 student를 가르킨다. ex=student.이름 )

아래 코드와 같이 입력하면 Student 생성자 함수로 생성된 객체는 이름, 국어, 수학, 영어, 과학 속성을 갖는다.

function Student (name, korean, math, english, science) {
    this.이름 = name;
    this.국어 = korean;
    this.수학 = math;
    this.영어 = english;
    this.과학 = science;
}
var student = new Student('남궁댕', 95, 90, 80, 70);

 

생성자 함수 내부에 메서드를 만드는 방법은 속성을 만드는 방법과 같다.

아래 코드와 같이 this키워드로 속성을 생성하고 함수를 넣어준다.

function Student (name, korean, math, english, science) {
    this.이름 = name;
    this.국어 = korean;
    this.수학 = math;
    this.영어 = english;
    this.과학 = science;
    
    this.getSum = function () {
        return this.국어 + this.수학 + this.영어 + this.과학;
    }
    this.getAverage = function () {
        return this.getSum() / 4;
    }
    this.toString = function () {
        return this.이름 + '\t' + this.getSum() + '\t' + this.getAverage();
    }
}
var student = new Student('남궁댕', 95, 90, 80, 70);

 

이전 포스팅과 마찬가지로 학생들의 총점 및 평균을 출력하는 로직을 구현해본다.

객체를 생성하는 부분을 제외하고는 동일하다.

function Student (name, korean, math, english, science) {
    /* 생략 */
}
var student = new Student('남궁댕', 95, 90, 80, 70);

var students = [];

students.push(new Student('안준언',90,95,100,80));
students.push(new Student('이건희',90,85,80,80));
students.push(new Student('황병선',90,90,100,90));
students.push(new Student('유재혁',80,100,70,95));
students.push(new Student('남궁댕', 95, 90, 80, 70));

var output = '이름\t총점\t평균\n';
for (var i in students) {
    output += students[i].toString()+'\n';
}
alert(output);

코드를 작성하고 실행하면 객체를 일반 함수로 생성했던 결과와 동일한 결과를 출력한다.

 

var student = new Student( )

          ──────                   ───────

          객체, 인스턴스                    생성자 함수

 

Student( ) 함수는 new 키워드로 객체를 생성하므로 '생성자 함수(Constructor)' 이다.

또한 Student 생성자 함수로 만든 객체 student를 객체(Object) 또는 인스턴스(Instance) 라고 부른다.

 

instanceof 키워드

객체를 생성하고 해당 객체가 어떤 생성자 함수로 생성됐는지 확인할 때 instanceof 키워드를 사용한다.

instanceof 키워드 사용법은 아래 코드와 같이 객체 식별자명과 생성자함수명을 기준으로 비교한다.

var student = new Student();

alert(student instanceof Student);

 

아래와 같이 코드를 구현하여 실행하면 student객체는 Student 생성자 함수의 인스턴스 이므로 첫번째 경고창에만 true를 출력한다.

function Student (name, korean, math, english, science) {
    this.이름 = name;
    this.국어 = korean;
    this.수학 = math;
    this.영어 = english;
    this.과학 = science;
}
var student = new Student('남궁댕', 95, 90, 80, 70);

alert(student instanceof Student);
alert(student instanceof Number);
alert(student instanceof String);
alert(student instanceof Boolean);

 

 

프로토타입

 앞서 구현한 생성자 함수는 일반 함수를 사용하여 객체를 생성한 것과 차이가 없다.

일반함수와 생성자함수로 만들었던 객체는 이름, 국어, 수학, 영어, 과학 속성을 포함하고 getSum( ), getAverage( ), toString( ) 메서드가 모두 있었다.

 객체 내부의 속성들은 모든 객체가 다른 값을 가지지만 메서드는 모두 같은 값을 갖는다. (메서드 기능이 같다.)

각 객체를 생성할때마다 동일한 함수를 계속 생성했던 것이다.

 만약 다루는 자료의 수가 증가해 천개 이상의 객체를 만든다면 같은 함수를 천번씩 생성하는 일이 발생하여 메모리를 쓸데없이 잡아먹는 굉장히 비효율적인 일이 발생한다. (물론 오류는 발생하지 않는다.)

 

 이러한 문제를 해결하기 위해 자바스크립트느 프로토타입Prototype 이라는 공간을 만들었다.

프로토타입은 생성자 함수로 생성된 객체가 공통으로 가지는 공간이다.

쉽게말해 객체를 생성할 때 메서드는 모두 프로토타입에 저장된다. (생성자 함수 or 일반함수 or 객체 직접 선언)

 이와같은 원리로 메서드를 하나만 생성해도 모든 객체가 해당 메서드를 사용할 수 있게 된다.

따라서 생성자 함수로 객체를 만들 때에는 생성자 함수 내부에 속성만 넣는다.

 또한, 프로토 타입은 우리가 만드는것이 아니다.

함수 안에 자동으로 만들어지는 배열 arguments 내장객체와 마찬가지로 prototype도 자바스크립트의 내장객체이다.

 

프로토타입으로 메서드를 객체에 넣는 방법은 아래 코드와 같다.

function Student (name, korean, math, english, science) {
    this.이름 = name;
    this.국어 = korean;
    this.수학 = math;
    this.영어 = english;
    this.과학 = science;
}

Studnet.prototype.getSum() = function() { };
Studnet.prototype.getAverage() = function() { };
Studnet.prototype.toString() = function() { };

var student = new Student();

프로토타입을 사용하면 기존 객체에 추가로 메서드를 제공할 수 있다.

 

new 키워드

생성자 함수로 객체를 생성할 때는 모두 new 키워드를 사용했다.

function Constructor(value) {
    this.value = value;
}
var constructor = new Constructor('Hello');
alert(constructor.value);
function Constructor(value) {
    this.value = value;
}
var constructor = Constructor('Hello');
alert(value);

위의 두 코드는 모두 같은 결과물인 Hello 문자열을 출력한다.

차이점이라고는 new키워드를 사용하지 않은 것과 constructor 객체의 value속성이 아닌 일반 변수 value를 사용했다.

 

일반적인 경우 this 키워드를 사용하면 window 객체를 나타낸다.

만약 일반적으로 함수를 호출하듯 new 키워드를 사용하지 않으면, 함수를 실행하는 동안 window객체에 속성을 추가한 것이 된다.

new 키워드를 사용했을 때 비로서 객체를 위한 공간인 prototype을 생성하고 this 키워드가 바로 prototype 공간을 의미하게 된다.

ex) var student = new Student( ); 일 경우 student인스턴스가 prototype객체의 메모리영역을 사용하게 되고 해당 메모리 영역을 참조하게 된다.

객체 내부에서 this를 사용하면 객체 자신(prototype)을 가리키고 객체 외부에서 this를 사용하면 window객체를 가리킨다고 이해하면 쉽다.

 

못믿겠으면 직접 찍어봐.

console.log(this);
function Constructor(value) {
    this.value = value;
    console.log(this);

}
var constructor = new Constructor('Hello');

 

따라서 new 키워드를 사용하지 않고 함수를 구현하면 constructor객체의 value속성이 아닌 window객체에 속성을 추가하여 사용하게 된 셈.

 

var array = Array();

배열 객체도 위 코드처럼 new 키워드를 사용하지 않아도 배열이 생성된다.

하지만 이때 window객체를 활용하게 된 것인지는 정확히 모르겠다............ 유추만...

728x90
반응형