본문 바로가기
JavaScript & TypeScript

[javascript] 사용자 정의 생성자 함수

by 대박플머 2016. 2. 18.

객체 리터럴 패턴이나 내장 생성자 함수를 쓰지 않고, 직접 생성자 함수를 만들어 객체를 생성할 수 있다.

1
2
var adam = new Person("Adam");
adam.say(); // "I am Adam"
cs

이런 형태는 객체지향 언어에서 클래스를 사용하여 객체를 생성하는 방식과 상당히 유사하다. 그러나 문법은 비슷해도 자바스크립트에서는 클래스라는 것이 없으며 위의 예제의 Person은 그저 보통 함수일 뿐이다. 

아래 예제는 Person의 함수이다. 

1
2
3
4
5
6
var Person = function (name){
    this.name = name;
    this.say = function(){
        return "I am " + this.name;
    };
};
cs

new와 함께 생성자 함수를 호출하면 함수 안에서 다음과 같은 일이 일어난다. 

- 빈 객체가 생성된다. 이 객체는 this라는 변수로 참조할 수 있고 해당 함수의 프로토타입을 상속받는다. 

- this로 참조되는 객체에 포로퍼티와 메서드가 추가된다. 

- 마지막에 다른 객체가 명시적으로 반환되지 않을 경우, this로 참조된 객체가 반환된다. 

아래 예제는 이면에서 진행되는 부분을 주석으로 표기한 것이다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
var Person = function (name){
    // 객체 리터럴로 새로운 객체를 생성한다. 
    // var this = {};
 
    // 프로퍼티와 메서드를 추가한다.
    this.name = name;
    this.say = function(){
        return "I am " + this.name;
    };
 
    // this를 반환한다. 
    // return this;
};
cs

위의 예제에서 간단히 say()라는 메서드를 this에 추가했다. 결과적으로 new Person()을 호출할 때마다 메모리에 새로운 함수가 생성된다. say()라는 메서드는 인스턴스별로 달라지는 게 아니므로(재사용되는 멤버) 이런 방식은 비효율적이다. 이런 경우 Person의 프로토타입에 추가하는 것이 더 낫다. 

1
2
3
Person.prototype.say = function(){
    return "I am" + this.name;
}
cs

추가 적으로 생성자의 반환 값에 대해 알아보겠다. 

생성자 함수를 new와 함께 호출하면 항상 객체가 반환된다. 기본값은 this로 참조되는 객체다. 생성자 함수 내에서 아무런 프로퍼티나 메서드를 추가하지 않았다면 '빈'(즉 생성자의 프로토타입에서 상속된 것 외에는 '비어 있는') 객체가 반환될 것이다. 

함수 내에 return문을 쓰지 않았더라도 생성자는 암묵적으로 this를 반환한다. 그러나 반환 값이 될 객체를 따로 정할 수도 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var Objectmaker = function(){
    // 생성자가 다른 객체를 대신 반환하기로 결정했기 때문에
    // 다음의 'name' 프로퍼티는 무시된다. 
    this.name = "This is it";
 
    // 새로운 객체를 생성하여 반환한다. 
    var that = {};
    that.name = "And that's that";
    return that;
};
 
// 테스트 
var o = new Objectmarker();
console.log(o.name); // "And that's that"
cs

위의 예제에서 볼수 있듯이 어떤 객체라도 (객체이기만 하면) 반환할 수 있다. 객체가 아닌 것 (예를 들면 문자열이나 false, ture)을 반환하려고 시도하면, 에러가 발생하진 않지만 그냥 무시되고 this에 의해 참조된 객체가 대신 반환된다.