Home prototype-중급자로 가기 위한 여정
Post
Cancel

prototype-중급자로 가기 위한 여정

5. proto vs prototype

우선 설명하기에 앞서 생성자 함수를 2개 만들자

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name, first, second) {
  this.name = name;
  this.first = first;
  this.second = second;
}

function PersonPlus(name, first, second, third) {
  Person(name, first, second);
  this.third = third;
}

var go = new PersonPlus("go", 50, 60, 90);

그리고 person을 personplus에 상속한다고 할때 위의 코드처럼하면 상속이 안된다. person이 아직 new를 통해서 객체화되지 않았기 때문에다. 그냥 일반 함수를 호출한것일뿐.

여기서 중요한것은 this를 어떻게 실현시킬것인가이다. 바로 call 함수를 사용하는것! “이미 객체인” PersonPlus 함수의 this를 person안에다가 호출하여 Person에 대입하는것이다.

1
2
3
4
function PersonPlus(name, first, second, third) {
  Person.call(this, name, first, second);
  this.third = third;
}

그리고 person생성자에 sum을, personplus 생성자에 avg를 함수를 추가하고 싶다고 하자. 또한 new를 통해서 Personplus 함수를 모체로 하는 kim이라는 새로운 객체를 만들고 싶다.

1
2
3
4
5
6
7
8
9
Person.prototype.sum = function () {
  return this.first + this.second;
};

PersonPlus.prototype.avg = function () {
  return (this.first + this.second + this.thrid) / 3;
};

var kim = new PersonPlus("kim", 10, 20, 30);

그리고 PersonPlus 생성자 함수에다가 person의 sum 함수를 상속하고 싶다. 여기서 복잡해진다. 먼저 각 객체안에 default로 담겨진 property가 있다. 바로 __proto__ 이다. 그 __proto__의 관계와 , 특히 proto와 prototype의 관계를 잘 이해해야한다. 근데..이게 무슨 개소리야 할것이다.

이고잉님이 정말 친절하게 그림으로 잘 설명해주셨다. 아래 그림을 살펴보자.

prototype

우선 kim.avg()를 입력해보자. 그럼 컴퓨터는 우선 kim 안에서 avg()를 찾으려고 할 것이다. 없으면 kim안에 있는 __proto__ 함수에서 찾으려고 할 것이다. 거기도 없으면 오류가 발생한다. proto 링크의 방향은 이런식으로 형성된다. avg() 함수같은 경우 kim의 __proto__안에 있으므로 문제없다. 문제는 kim.sum() 을 호줄하려고 할때이다. __proto__에도 없으므로 오류가 발생한다.그럼 proto링크를 생각해봤을때 PersonPlus.prototype.__proto__ = Person.prototype 라는 로직을 짜면 문제가 없을것이다.

1
2
3
4
5
6
7
8
PersonPlus.prototype.__proto__ = Person.prototype;

//또는

PersonPlus.prototype.sum = Person.prototype.sum;

console.log(kim.sum());
// 110

근데 __proto__는 비공식적인 방법이고 좀더 안전하고 효율적인 Object.create()를 사용해주자.

1
2
3
PersonPlus.prototype = Object.create(Person.prototype);
console.log(kim.avg());
// avg() is not a function

근데 요렇게 바꾸면 personplus의 prototype이 person의 prototype으로 상속된다. 그러면 기존에 personplus.prototype에 추가한 avg() 함수가 덮어씌어지면서 avg() 함수가 없어진다. 따라서

1
2
3
4
5
6
7
8
9
10
11
12
13
PersonPlus.prototype.__proto__ = Object.create(Person.prototype);
console.log(kim.avg());
// 66.66666

//또는

PersonPlus.prototype = Object.create(Person.prototype);
PersonPlus.prototype.avg = function () {
  return (this.first + this.second + this.third) / 3;
};

console.log(kim.avg());
// PersonPlus.prototype를 교체한다음 avg()를 다시 추가하면 사용가능하다.

이렇게 해야 avg() 함수도 살아남으면서 person.prototype 안에 있는 sum 함수도 사용할 수 있게 된다.

P.S: 참고로 객체의 모체를 알고 싶다하면.(너의 정체, 원래 클래스가 뭐냐..?) 객체.constructor 라고 하면 된다. 다시 위의 그림을 보자. constructor 함수는 다시 모체 객체를 가리키고 있기 때문이다. 여기서 더 나아가 생각해보면

1
PersonPlus.prototype = Object.create(Person.prototype);

라고 한다면 PersonPlus.prototype은 Person.prototype 로 교체되었기 때문에 PersonPlus.prototype.constructor = Person 이 될것이다.

사실 함수객체끼리 상속하기 보다 클래스를 만들어서 super()를 사용해 상속하는게 훨씬 깔끔하고 쉽다. 근데 proto 링크를 알아두는 것은 자바스크립트 중급자로 가기위한 필수 관문이므로 자바스크립트를 주 언어로 한다면 꼭 알아두어야 할것이다.

This post is licensed under CC BY 4.0 by the author.