2012-04-24 3 views
6

서비스에서 돌아 오는 항목의 배열이 있습니다. 나는 모든 Item 인스턴스에 대해 계산 된 관찰 가능 (observable)을 정의하려고하고있다. 그래서 나의 본능이 그것을 프로토 타입에 넣으라고 말한다.KnockoutJS에서 가능한 프로토 타입에 대한 관측 값을 계산합니까?

계산 된 관측 가능의 경우 : 시스템이 포인트를 계산하지만 사용자가 계산 된 값을 무시하도록 선택할 수 있습니다. 사용자가 재정의를 제거 할 경우 계산 된 값을 유지해야합니다. 또한 사용자 지정 및 계산 된 포인트를 합쳐서 합계를 합산해야합니다.

나는 다음을 수행 매핑을 사용하고 있습니다 :

var itemsViewModel; 
var items = [ 
    { 'PointsCalculated' : 5.1 }, 
    { 'PointsCalculated' : 2.37, 'PointsFromUser' : 3 } 
]; 

var mapping = { 
    'Items' : { 
     create : function(options) { 
      return new Item(options.data); 
     } 
    } 
}; 

var Item = function(data) { 
    var item = this; 
    ko.mapping.fromJS(data, mapping, item); 
}; 

Item.prototype.Points = function() { 
    var item = this; 
    return ko.computed(function() { 
     // PointsFromUser may be 0, so only ignore it if the value is undefined/null 
     return (item.PointsFromUser != null) ? item.PointsFromUser : item.PointsCalculated; 
    }); 
}; 

ko.mapping.fromJS(items, mapping, itemsViewModel); 

지금 작동하는 방법을, 나는 계산 관찰을 반환하는 익명 함수를 호출해야합니다. 이는 각 바인딩에 대해 계산 된 관찰 가능 항목의 새 인스턴스를 만드는 것으로 보입니다.이 인스턴스는 프로토 타입에 놓는 지점의 대부분을 무효화합니다. 그리고 관찰 대상에 접근 할 때마다 사용할 괄호의 수를 해독해야하는 것은 약간 성가신 일입니다.

다소 허약합니다. 내가 코드() 포인트에 액세스하려고하면 그 대신 항목의, DOMWindow를 가리 킵니다()의 컨텍스트를 변경하기 때문에, 나는

var points = 0; 
var p = item.Points; 
if (p && typeof p === 'function') { 
    points += p(); 
} 

할 수 없습니다.

계산에 create()를 넣으면 컨텍스트를 캡처 할 수 있지만 각 개체 인스턴스에 메서드 복사본이 있습니다.

나는 Michael Best의 Google 그룹스 게시물 (http://groups.google.com/group/knockoutjs/browse_thread/thread/8de9013fb7635b13)을 발견했습니다. 프로토 타입은 "활성화 된"상태에서 새로운 계산 된 관찰 가능 값을 반환합니다. 나는 "활성화"(어쩌면 Objs)라고 부르는 것을 알아 내지 못했지만, 객체 당 한 번 발생한다고 추측하고 있는데, '이것이'어떤 범위를 얻을지 실마리가 없습니다.

이 시점에서 저는 게시 된 문서에서 사용할 수있는 것보다 앞서 있다고 생각합니다. 그러나 나는 여전히 소스에서 진행중인 작업을 해독하려고 노력하고 있습니다.

답변

7

자바 스크립트 클래스의 각 인스턴스에 ko.computed 함수의 인스턴스를 갖고 싶지는 않지만 ko의 기능이 실제로 구현되지는 않는다는 것을 언급했습니다. ko.computed 또는 ko.observable을 사용하면 일반적으로 클래스 인스턴스간에 공유하고 싶지 않은 private 변수에 대한 특정 메모리 포인터를 만듭니다 (드문 경우이지만).

내가 이런 일을 수행

var Base = function(){ 
    var extenders = []; 

    this.extend = function(extender){ 
     extenders.push(extender); 
    }; 

    this.init = function(){ 
     var self = this; // capture the class that inherits off of the 'Base' class 

     ko.utils.arrayForEach(extenders, function(extender){ 

      // call each extender with the correct context to ensure all 
      // inheriting classes have the same functionality added by the extender 
      extender.call(self); 
     }); 
    }; 
}; 

var MyInheritedClass = function(){ 
    // whatever functionality you need 

    this.init(); // make sure this gets called 
}; 

// add the custom base class 
MyInheritedClass.prototype = new Base(); 

다음 (당신의 MyInheritedClass의 각 인스턴스에 인스턴스 기능이어야합니다) 계산 된 관찰 가능한 위해 내가 너무 같은 extender에서 그들을 선언

MyInheritedClass.prototype.extend(function(){ 

    // custom functionality that i want for each class 
    this.something = ko.computed(function() { 
     return 'test'; 
    }); 
}); 

쉽게, 수 귀하의 예를 감안하고 Base 클래스는 위에서 정의한 수행

var Item = function(data) { 
    var item = this; 

    ko.mapping.fromJS(data, mapping, item); 

    this.init(); // make sure this gets called 
}; 
Item.prototype = new Base(); 

Item.prototype.extend(function() { 
    var self = this; 

    this.Points = ko.computed(function() { 

     // PointsFromUser may be 0, so only ignore it if the value is undefined/null 
     return (self.PointsFromUser != null) ? 
       self.PointsFromUser : self.PointsCalculated; 
    }); 
}; 

Item 클래스의 모든 인스턴스는 Points 속성을 가지며 인스턴스 당 ko.computed 논리를 올바르게 처리합니다.

+0

감사합니다. 나는 .extend()의 목적이 단지 클릭 된 것으로 생각한다. 이것은 내 범위 지정/이중 함수 호출 문제를 멋지게 해결하고, Knockout이 원형에 실제 계산 된 관찰 가능을 유지하지 못하도록하겠다. –

+0

에릭, 더 설탕 냄새가 나는 버전을 제공해 줄 수 있습니까? 이미 프로토 타입 체인 설정을 수행하는 childClass = BaseClass.extend (function() {/*...*/})와 같은 것입니까? 각 클래스 인스턴스에 대해 수동으로 수행해야하는 것은 조금 이상합니다 ... – fbuchinger

+0

기본적으로 상속 된 생성자에 '확장'정적 함수를 넣을 수없는 이유가 표시되지 않습니다. ' SubClass.extend = function (익스텐더) {SubClass.prototype.extend (익스텐더); }; – ericb

0
Item.prototype.Points = function() { 
var item = this; 
return ko.computed(function() { 
    // PointsFromUser may be 0, so only ignore it if the value is undefined/null 
    return (item.PointsFromUser != null) ? item.PointsFromUser : item.PointsCalculated; 
}); 

}};

0
Item.prototype.extend(function() { 
var scope = this 
this.Points = ko.computed(function() { 
    return (this.PointsFromUser != null) ? 
      this.PointsFromUser : this.PointsCalculated; 
}, scope); 
};