Knockout.js 在KnockoutJS中,原型上的计算观察值是否可行?

Knockout.js 在KnockoutJS中,原型上的计算观察值是否可行?,knockout.js,knockout-mapping-plugin,Knockout.js,Knockout Mapping Plugin,我从服务中得到了一系列物品。我试图为每个项目实例定义一个可计算的可观测值,所以我的直觉告诉我把它放在原型上 计算的可观测值的一种情况是:系统计算点,但用户可以选择覆盖计算值。我需要保持计算值可用,以防用户删除覆盖。我还需要合并用户分配和计算的点,并将总数相加 我正在使用映射来执行以下操作: var itemsViewModel; var items = [ { 'PointsCalculated' : 5.1 }, { 'PointsCalculated' : 2.37, 'Po

我从服务中得到了一系列物品。我试图为每个项目实例定义一个可计算的可观测值,所以我的直觉告诉我把它放在原型上

计算的可观测值的一种情况是:系统计算点,但用户可以选择覆盖计算值。我需要保持计算值可用,以防用户删除覆盖。我还需要合并用户分配和计算的点,并将总数相加

我正在使用映射来执行以下操作:

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);
现在的工作方式是,我必须调用匿名函数来返回计算出的可观测值。这似乎为每个绑定创建了一个新的计算可观察实例,这破坏了将其放在原型上的大部分要点。每次我访问一个可观察对象时,必须破译要使用多少括号,这有点烦人

它也有点脆弱。如果我试图在代码中访问Points(),我就做不到

var points = 0;
var p = item.Points;
if (p && typeof p === 'function') {
    points += p();
}
因为这会将Points()的上下文改为DOMWindow,而不是item

如果我将computed in create()放在映射中,我可以捕获上下文,但是每个对象实例上都有该方法的副本

我找到了Michael Best的Google Groups post()。原型在“激活”时返回一个新的计算可观测值。我还没有弄清楚什么叫“激活”(可能是Objs?),但我猜每个对象仍然会发生一次,我也不知道“这个”会有什么作用域


在这一点上,我相信我已经超越了已发布文档中的可用内容,但我仍在努力破解源代码中的内容。

您提到您不希望在javascript类的每个实例上都有一个
ko.computed
函数的实例,这与ko的功能是如何构建的并不匹配。当您使用
ko.computed
ko.observable
时,它们会创建特定的内存指针,指向内部的私有变量,您通常不希望在类实例之间共享这些变量(尽管在极少数情况下可能)

我是这样做的:

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;
    });
};
然后,您的
类的所有实例都将具有
Points
属性,并且它将正确处理每个实例的
ko.computed
逻辑

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;
});

})

谢谢。我认为刚才单击的.extend()的用途。这很好地解决了我的作用域/双函数调用问题,我相信你的话,Knockout不会让我在原型上保持实际的计算可观察性。eric,你能提供一个更“糖化”的版本吗?像childClass=BaseClass.extend(function(){/*…*/})这样的东西已经在进行原型链设置了吗?必须为每个类实例手动执行此操作有点奇怪……我不明白为什么不能在继承的构造函数上放置“扩展”静态函数,只要它基本上是这样做的:
SubClass.extend=function(extender){SubClass.prototype.extend(extender);}
Item.prototype.extend(function () {
var scope = this
this.Points = ko.computed(function () {
    return (this.PointsFromUser != null) ? 
           this.PointsFromUser : this.PointsCalculated;
}, scope);
};