javascript 객체를 잘못 구현하는 방법 중 하나는 인스턴스마다 저장해야할 데이터를 실수로 프로토타입에 저장하는 것이다.
만약 트리 데이터 구조를 구현하는 클래스는 아마도 각 노드마다 자식들의 배열을 포함할 것이다. 근데 자식 배열을 프로토타입에 저장한다면 어떻게 될까?
function Tree(x){
this.value = x;
}
Tree.prototype = {
children:[],
addchild:function(x){
this.children.push(x);
}
};
이 클래스로 트리를 생성해 보자
var left = new Tree(2);
left.addChild(1);
left.addChild(3);
var right = new Tree(6);
right.addChild(5);
right.addChild(7);
var top = new Tree(4);
top.addChild(left);
top.addChild(right);
top.children; // [1,3,5,7,left, right]
addChild를 호출할 때마다. Tree.prototype.children에 값을 덧붙이게 되고 어디서든지 addChild를 호출하면 호출 순서에 따라 노드들을 포함하게 된다.
결과적으로 Tree객체는 논리에 맞지 않는 상태가 된다.
인스턴스의 상태를 프로토타입에 저장한 경우
가장 좋은 방법은 다음과 같이 각 인스턴스 객체에 구분된 children 배열을 생성하는 것이다.
//생성자 함수
function Tree(x){
this.value = x;
this.children = []; //인스턴스 상태;
}
// 프로토타입 설정
Tree.prototype = {
addChild:function(){
this.children.push(x);
}
};
인스턴스의 상태를 인스턴스 객체에 저장한 경우
이제 이전과 동일한 예제 코드를 실행해보면 다음처럼 예상된 상태값을 얻게 된다.
상태를 나타내는 데이터는 공유시 문제를 일으킬 소지가 있지만 메서드는 보통 한 클래스에 속하는 다수의 인스턴스간에 공유되어도 안전하다.
// 프로토타입 설정
Tree.prototype = {
addChild:function(){
this.children.push(x);
}
};
인스턴스의 상태를 this
를 통해 참조하는것 외에는 상태값을 가지지 않기 때문이다. 또 해당 this가 인스턴스 객체(left, right, top)에 바인딩 되었다는 것을 보장하기 때문에 공유된 메서드는 인스턴스의 상태 값에 안전하게 접근할 수 있다.
수정이 불가능한 데이터는 프로토 타입으로 공유하는 것이 안전하며, 또 한 데이터를 진짜로 공유할 의도라면 원칙적으로 프로토타입에 저장할 수 있다.
이 글을 통해 많은 것을 배웠습니다.