2014-12-19 4 views
5

내 앱에서 버그를 잡으려고 많은 시간을 보냈습니다. 결국 나는 행동이 매우 이상하게 보일 정도로이 코드 조각을 구분했다.백본의 속성으로 이동

var Model = Backbone.Model.extend({ 
    myProperty: [] 
}); 

var one = new Model(); 
var two = new Model(); 
one.myProperty.push(1); 
console.log(two.myProperty); //1!! 

그 이유는 무엇입니까? 왜 그렇게 행동합니까? 코드에서 이러한 유형의 버그를 피하는 방법은 무엇입니까?

답변

3

상속은 프로토 타입입니다 - 객체는 prototype chain에서 높은 속성에 직접 참조 할 수 있습니다.

당신의 예에서

, onetwo 모두 공통의 프로토 타입을 공유하고 myProperty는 그래서 그들은 모두 Model.protoype.myProperty를 직접 참조에 대한 자신의 값을 제공하지 않습니다.

인스턴스화하는 각 모델에 대해 myProperty 배열을 새로 만들어야합니다. Model.initialize은 이런 종류의 초기화를위한 관용적 인 장소입니다. 우선 constructor이 불필요하게 복잡합니다. - 간단한 객체를 사용한다면 같은 발생할 것

var Model = Backbone.Model.extend({ 
    defaults: function() { 
     return { 
     myProperty: [] 
     } 
    } 
}); 

defaults 함수는 것이 중요합니다 :

var Model = Backbone.Model.extend({ 
    initialize: function() { 
     this.myProperty = []; 
    } 
}); 

또는 당신이 모델의 속성으로 myProperty을 만들 수 공유 참조 문제.

+0

감사합니다. 나는 초기화에서 myproperty를 초기화 할 것을 고려했다. (동어 반복을 위해 유감스럽게 생각한다.) 그러나 그것은 다른 방법으로 그것을 초기화하는 것이 다른 결과를 가져온다는 것이 이상했다. 적어도 그것은 의미 상으로 명백하지 않습니다 ...하지만 백본이 아니라 자바 스크립트 문제입니다. – alexb

+1

정확 하 게 요점은 그것이 백본의 것이 아니라 JavaScript라는 것입니다. 본질적으로 문제는 아니며 실제로 프로토 타입 시스템에는 완전히 필요합니다. 모델 인스턴스가 없으면 모델 인스턴스는 많은 중복 객체를 만들지 않고 메서드 나 공통 속성을 공유 할 수 없습니다. 이 유형의 버그는 매우 자주 발생합니다! – joews

1

문서는 말한다 :

생성자/

모델의 인스턴스를 생성, 당신은 속성의 초기 값을 전달할 수있는 새로운 모델 ([속성], [옵션]) 초기화 모델에 설정됩니다. initialize 함수를 정의하면 모델을 만들 때 호출됩니다.

드문 경우이지만, 궁금해지기를 원하면 모델의 실제 생성자 함수를 바꿀 수있는 생성자를 재정의해야 할 수도 있습니다.

그래서, 문서를 다음, 당신은 당신의 경우 실행을 얻기 위해 같은 것을 할 싶어 :

var Model = Backbone.Model.extend({ 
    initialize: function() { 
     this.myProperty = []; 
    } 
}); 

소스 : http://backbonejs.org/#Model-extend

+2

왜'initialize'와 같은 기능을 제공하기 위해'constructor'을 오버라이드하겠습니까? – Jivings

+1

@Jivings 문서 페이지에서 복사하기 때문에. 포스트에'initialize'을 편집했습니다. – blgt

1

사실의 myProperty가 배열이기 때문에, 그리고 알다시피 배열은 참조로 저장됩니다. 그냥 다음 코드를 고려 테스트 :

var Model = Backbone.Model.extend({ 
myProperty: [], 
messege: '' 
}); 

var one = new Model(); 
var two = new Model(); 

one.messege = 'One!'; 
two.messege = 'Two!'; 

console.log(one.messege); // 'One!' 
console.log(two.messege); // 'Two!' 

이 주위의 대안은 될 수있다 : 자바 스크립트에서

var Model = Backbone.Model.extend({ 
    constructor: function() { 
    this.myProperty = []; 
    Backbone.Model.apply(this); 
    } 
}); 

var one = new Model(); 
one.myProperty.push(1); 

var two = new Model(); 
console.log(two.myProperty); // [] 
+1

'one'과 'two'가 참조를 공유하는 이유는 prototypical 상속입니다. 자식 개체는 부모 속성에 대한 참조를 공유합니다. – joews

+1

또한 Backbone은 이러한 종류의 초기화에'Model.initialize'를 제공합니다. 'constructor'을 오버라이드하는 것은 과도합니다.Backbone docs는 "드문 경우이지만, 당신이 공상을 얻으려고한다면, 당신은 생성자를 오버라이드하고 싶을 것입니다 ..."라고 말합니다. 이는 드문 경우는 아니며 '초기화'가 의도 한 정확한 사용 사례입니다. – joews

+0

@joews 맞습니다.이 경우에는 '초기화'를 선택하는 것이 좋습니다. – sadrzadehsina