[Javascript] new와 생성자 함수

Posted by 열정보이
2019. 7. 14. 20:18 Javascript

 

오늘은 생성자 함수에 대해서 정리해보려고 한다.

ES6 기준으로 Javascript에는 class 라는것이 생겼다. 하지만 ES6는 IE에서 지원하지 않으므로, IE도 서비스 대상일 경우 ES5 기준으로 코딩을 하면 되는데, 이때 ES5에서는 class 대신 생성자 함수를 사용하여 Java에서의 class와 같은 역할을 하게 할 수 있다.

 

물론 ES6의 class 기반은 생성자 함수라고 한다.

그럼 생성자 함수를 본격적으로 파헤쳐 보자..!

 

 

 

생성자 함수와 new

Javascript 에도 Java와 같이 new가 존재하는데, 주로 아래와 같이 사용한다.

 

 var tempObj = new Object();

 

Object뒤에 ()가 붙어있는것을 보니 함수라고 추측할 수 있다.

그리고 앞에 new가 붙어있는 것을 보고 우리는 무언가 '새로운 것' 을 반환한다고 추측할 수 있다. 그렇다 new Object() 와 같이 명시할 경우, 새로운 Object의 빈 객체를 반환한다.

이렇게 new를 붙여서 자신에 대한 새로운 빈 객체를 반환하는 함수를 '생성자 함수' 라고 한다.

 

더 이해하기 쉽게 아래 코드를 보도록 하자.

 

 function Student(age,name){
    this.age = age;
    this.name = name;
 };

 

위와 같은 함수를 생성자 함수라고 한다. 어떻게 알았냐고 한다면, 생성자 함수의 특징으로 이름의 첫글자는 항상 대문자여야 한다 라는 약속이 있기 때문이다.

물론 소문자로 사용해도 에러가 나진 않는다. 하지만 대문자로 써줌으로써, 이 함수가 생성자 함수인지, 일반 함수인지 구분할 수 있게 약속을 정한것이라고 한다.

 

그럼 저렇게 만들어진 생성자 함수를 사용해보자.

 

 function Student(age,name){
 	this.age = age;
 	this.name = name;
 };

 var Daesik = new Student(27,'Daesik');
 console.log(Daesik);

 

Daesik 이라는 변수에 나이는 27, 이름은 Daesik 이라는 값을 넣은 새로운 객체를 생성해 넣어주었다. 그리고 console.log 를 이용해 결과를 확인해 보면 우리가 원하는 대로 값이 들어간 것을 확인할 수 있다.

 

어? 잠시만

함수이지만 우리는 return 값을 명시하지 않았는데 객체가 반환되었네?

 

그렇다. 생성자 함수는 return 값을 명시하지 않더라도, new를 통해 생성한 객체를 반환한다.

생성자 함수로 사용될 함수라면 굳이 return 값을 명시해주지 않아도 된다.

 

한 가지 더 보도록 하면, 함수 내부의 값들을 this.age, this.name 과 같이 this를 앞에 명시해주었다. 왜 그런지 궁금한 사람은 this 대신 Student 와 같이 다른 값을 명시해주고 생성해보면 쉽게 알 수 있다.

 

new 를 통해 생성자 함수에 대한 객체를 생성할 때, 생성자 함수 내부의 this는 새로 생긴 빈 객체에 바인딩 된다. 그렇기 때문에 생성자 함수 내부에 명시되어있는 변수들에 this. 를 붙여 해당 객체의 변수로 만들어 주는 것이다.

 

 

 

생성자 함수를 왜 사용할까?

 

객체 지향 프로그래밍을 보면 class 가 있고, 해당 class에 new를 붙여 호출함으로 써, class에 영혼..? 을 불어 넣은 '객체' 를 생성하여 사용한다.

 

Javascript도 동일하다. 

ES6 이전 버전에서는 명시적으로 class 라는 것이 없었기 때문에 생성자 함수를 이용해 객체를 생성하여 쓰고 싶을 때마다 불러다 쓸 수 있게 사용한 것이다.

 

위에 명시한 것 처럼, 생성자 함수를 이용하여 객체를 생성할 경우 학생에 대한 객체를 생성할 때, new Student(age, name); 값만 명시해준 다면, 해당 학생의 고유 값을 가진 객체를 사용할 수 있다.

 

그렇지 않다면, 아래 처럼 번거롭게 사용하지 않았을까

 

 var daesik = { age : 27, name : 'daesik' };
 var junsik = { age : 23, name : 'junsik' };
 var dusik  = { age : 2 , name : 'dusik'  };

 

 

 

 

생성자 함수내부의 함수

 

생성자 함수가 클래스와 같은 역할을 한다면, 당연히 내부에 함수를 선언할 수 있어야 할 것이다. Student 를 좀 더 확장해보자.

 

 function Student(age,name,score){
    this.age = age;
    this.name = name;
    this.math = score.math || 0;
    this.kor  = score.kor  || 0;
    this.eng  = score.eng  || 0;

    this.getAvg = function(){
        return (this.kor + this.eng + this.math) / 3;
    };
 };
 
 var daesik = new Student(8,'Deasik',{math:60,kor:70,eng:100});
 daesik.getAvg();

 

변수뿐만이 아닌, getAvg 라는 함수가 생성되었다.

this.getAvg() 함수는 이 학생의 국어, 영어, 수학 점수의 평균 값을 반환해준다.

 

이때 해당 객체의 과목 점수들의 평균을 반환해야 하는 것 이기 때문에, 과목 앞에 this 를 붙여, 메서드를 호출하는 객체에 this를 바인딩하여 사용한다.

 

하지만 위와 같이 사용할 경우, 위 생성자 함수를 사용해 만든 모든 객체에 getAvg() 라는 함수가 생성된다. 우리는 getAvg() 함수를 사용만 하면 되지 객체마다 getAvg() 함수를 만드는 메모리 낭비는 피하고 싶을것이다.

 

그렇기 때문에 생성자 함수의 프로토타입에 함수를 선언해준다.

 

 function Student(age,name,score){
    this.age = age;
    this.name = name;
    this.math = score.math || 0;
    this.kor  = score.kor  || 0;
    this.eng  = score.eng  || 0;
 };
 
 Student.prototype.getAvg = function(){
 	return (this.kor + this.eng + this.math) / 3;
 };
 
 var daesik = new Student(10,'Daesik',{math:80,eng:90,kor:100});
 console.log(daesik);

 

위와 같이 실행해보면, daesik 이라는 객체에는 getAvg() 함수가 없는 것을 확인할 수 있을 것이다. 위와 같이 생성자 함수를 만듬으로써, 함수의 중복도 피하고 객체로써의 역할도 할 수 있는 생성자 함수를 사용할 수 있다.

 

프로토타입은 프로토타입 컨텐츠에서 자세히 적어보도록 하겠다.