3.9.2) 프로토타입
다음은 Person 객체를 3개 정의하고 출력하는 예제다.
no_prototype.htm |
function Person(name, age) { this.myName = name; this.myAge = age; this.toString = function() { return 'Person: ' + this.myName + ', ' + this.myAge; }; }
function main() { var p1 = new Person("kid", 10); var p2 = new Person("young", 20); var p3 = new Person("man", 30);
Log(p1.toString()); Log(p2.toString()); Log(p3.toString()); } |
실행하는 데에는 전혀 문제가 없는 단순한 예제다. 그러나 이 경우 Person 생성자 안에 toString 메서드를 정의하는 부분은 문제가 될 수 있다. Person 객체가 생성될 때마다, 즉 Person 생성자가 호출될 때마다 각 객체는 자신만의 toString 객체를 별도로 가지게 된다. 무명 함수는 함수 객체를 생성해서 반환하기 때문이다. 그림으로 보면 지금 main 내부는 다음 상태와 같다.
그런데 생각해보자. toString 메서드는 자신의 정보를 출력하는 메서드다. 객체가 가지고 있는 속성의 값이 달라질지언정, 객체가 달라진다고 출력하는 논리가 달라지지는 않는다. 따라서 같은 내용의 함수를 객체마다 가지고 있는 건 사실 불필요한 것이다. 후에 객체가 수십, 수백 개로 늘어나게 된다면 필요 없는 부분에 그만큼 메모리를 사용하게 되므로, 이는 개선해야만 하는 문제가 된다.
JavaScript의 모든 객체는 prototype이라는 숨겨진 객체를 가지고 있는데, 이 객체를 이용해 멤버를 공유할 수 있다. 이를 이용해 toString 메서드가 하나의 메서드를 가리키게 만든다면 위에서 보인 문제는 다음과 같이 해결이 된다.
그럼 바로 적용해보자.
prototype.htm |
function Person(name, age) { this.myName = name; this.myAge = age; } // prototype의 메서드로 toString을 정의합니다. Person.prototype.toString = function() { return 'Person: ' + this.myName + ', ' + this.myAge; };
function main() { var p1 = new Person("kid", 10); var p2 = new Person("young", 20); var p3 = new Person("man", 30);
Log(p1.toString()); Log(p2.toString()); Log(p3.toString()); } |
이와 같이 프로토타입의 필요성을 이해하고 사용 방법을 알 수 있었다.