在KnockoutJS中,原型上的可计算观察值是否可行? [英] Are computed observables on prototypes feasible in KnockoutJS?

查看:64
本文介绍了在KnockoutJS中,原型上的可计算观察值是否可行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从服务中返回了一系列商品.我试图为每个Item实例定义一个可计算的可观察值,所以我的直觉告诉我要将其放在原型上.

I have an array of items coming back from the service. I'm trying to define a computed observable for every Item instance, so my instinct tells me to put it on the prototype.

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

One case for the computed observable: the system calculates points, but the user can choose to override the calculated value. I need to keep the calculated value available in case the user removes the override. I also need to coalesce user-assigned and calculated points, and add up the totals.

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

I'm using mapping to do the following:

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

它现在的工作方式,我必须调用匿名函数以返回计算得到的可观察值.这似乎为每个绑定创建了一个可计算的可观察对象的新实例,这打破了将其放在原型上的大部分观点.而且每次我访问一个可观察对象时,都必须破译要使用多少个括号,这有点烦人.

The way it works now, I have to call the anonymous function to return the computed observable. That appears to create a new instance of the computed observable for each binding, which defeats most of the point of putting it on the prototype. And it's a little annoying having to decipher how many parentheses to use each time I access an observable.

它也有些脆弱.如果我尝试访问代码中的Points(),则无法完成

It's also somewhat fragile. If I attempt to access Points() in code, I can't do

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

因为将Point()的上下文更改为DOMWindow,而不是item.

because that changes to context of Points() to DOMWindow, instead of item.

如果将计算的结果放在映射的create()中,则可以捕获上下文,但是每个对象实例上都有一个方法的副本.

If I put the computed in create() in the mapping, I could capture the context, but then there's a copy of the method on each object instance.

我发现了迈克尔·贝斯特(Michael Best)的Google网上论坛帖子( http://groups. google.com/group/knockoutjs/browse_thread/thread/8de9013fb7635b13 ).原型在激活"时返回一个新的可观察到的可计算量.我还没有弄清楚什么叫激活"(也许是Objs?),但是我猜想它仍然对每个对象发生一次,而且我不知道这个"将得到什么作用域.

I've found Michael Best's Google Groups post (http://groups.google.com/group/knockoutjs/browse_thread/thread/8de9013fb7635b13). The prototype returns a new computed observable on "activate". I haven't figured out what calls "activate" (maybe Objs?), but I'm guessing it still happens once per object, and I haven't a clue what scope 'this' will get.

目前,我相信我已经超越了已发布文档中提供的功能,但我仍在努力从源头上解密正在发生的事情.

At this point, I believe I'm past what's available in published docs, but I'm still working up to deciphering what's going on from the source.

推荐答案

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

You mention that you don't want to have an instance of the ko.computed function on each instance of your javascript class, however, that won't really work with how ko's functionality has been built. When you use ko.computed or ko.observable they create specific memory pointers to private variables inside that you would not normally want to be shared across class instances (although in rare cases you might).

我做这样的事情:

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中声明它们,如下所示:

then for the computed observables (which HAVE to be instance functions on each instance of your MyInheritedClass) I just declare them in an extender like so:

MyInheritedClass.prototype.extend(function(){

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

鉴于您的示例和上面定义的Base类,您可以轻松地做到:

Given your example and the Base class defined above, you could easily do:

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逻辑.

Then all instances of your Item class will have a Points property, and it will correctly handle the ko.computed logic per instance.

这篇关于在KnockoutJS中,原型上的可计算观察值是否可行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆