[javascript] constructor function

Published: by Creative Commons Licence

생성자 함수

인스턴스를 생성하는 함수
생성자 함수의 prototype 프로퍼티는 앞으로 만들 인스턴스의 조상이 될 프로토타입을 가리킨다.
관례상 일반함수와 구분하기 위해 함수명을 대문자로 시작, 명사형으로 만든다.

new 생성자_함수명()

function Me(){
  this.age = 39;
  this.eat = function(food){
    console.log('eat ', food);
  }
}

let me = new Me(); // {age: 39, eat: ƒ}
me.age; // 39
me.eat('kiwi'); // eat kiwi

생성자 함수를 일반 함수로써 호출하면 인스턴스를 생성하지 않고 return문에 의한 리턴값이나 undefined를 리턴한다.

function Me(){
  this.age = 39;
  this.eat = function(food){
    console.log('eat ', food);
  }
  return 1;
}

let notMe = Me(); // 1

실제 Object() 함수는 아래와 같은 형태인데, 여기서 thisObject() 생성자 함수가 생성한 새 인스턴스를 의미한다.

function Object() {
  if (!(this instanceof Object)) { // this가 Object로부터 생성된 인스턴스가 아니면
    return new Object(); // Object 생성자 함수로 새 인스턴스를 생성하고 리턴해라.
  }
  ...
}

생성자 함수를 만들 때 위 조건문을 넣으면 생성자 함수로써 호출하지 않더라도 자동으로 인스턴스를 생성해서 리턴한다.
즉, 생성자 함수로 호출된 함수의 this는 함수의 소유자가 아니라 앞으로 리턴할 새 인스턴스를 의미한다.
일반 함수로 호출된 함수의 this는 함수를 소유한 (브라우저라면 최상위 객체인 window) 객체가 된다.

function Me(){
  if (!(this instanceof Me)) {
    return new Me();
  }
  this.age = 39;
  this.eat = function(food){
    console.log('eat ', food);
  }
}

let meme = Me(); // {age: 39, eat: ƒ}

this는 새 인스턴스를 가리키며 생성자 함수가 호출된만큼 새로 생성된다. 위의 eat()처럼 생성자 함수 내에서 this의 프로퍼티로 함수를 정의하면, 매 인스턴스가 생성될 때마다 eat() 함수가 새로 만들어지는 셈이 된다.
이 경우 메모리의 낭비를 초래하므로 어차피 재정의될 일 없는 프로퍼티라면 인스턴스의 프로퍼티보다 프로토타입의 프로퍼티로 정의하는 것이 낫다.

function Me(){
  if (!(this instanceof Me)) {
    return new Me();
  }
  this.age = 39; // 변할수 있는 값
}

Me.prototype.eat = function(food) { // function은 잘 변경하지 않으므로 프로토타입에 넣어 메모리 낭비 방지
	console.log('eat', food);
};

let me = new Me();

이렇게 정의하면 eat()은 Me 프로토타입에 딱 한 번만 정의되며, Me()에 의해 생성된 인스턴스는 이를 상속받는다.

프로토타입 체인

인스턴스의 프로퍼티에 접근할 때, 인스턴스에 없는 프로퍼티라면 부모(=프로토타입)에 있는 프로퍼티인지를 자동으로 탐색하는데, 이것이 프로토타입 체인이다.

me.eat('apple'); // "eat apple"
// 위 결과가 가능한 이유는, me에 eat()은 없지만 프로토타입 체인으로 부모가 갖고 있는 eat()을 찾아 실행했기 때문이다.