我用小提琴演示了我的问题:http://jsfiddle.net/sljux/zVg7R/3/
我有一个对象数组。为简单起见,假设每个对象都有一个名称和一个值数组,所有这些都是可观察的:
self.array = [
{
name: ko.observable("first"),
values: ko.observableArray([1, 2, 3])
},
{
name: ko.observable("second"),
values: ko.observableArray([2, 3, 4])
},
{
name: ko.observable("third"),
values: ko.observableArray([3, 4, 5])
}
];
从那个数组我需要过滤掉某些对象,并为每个对象添加一个额外的计算器,它计算所有值的总和。过滤部分对问题并不重要,因此不会这样做。问题是observable需要是每个对象的属性,并且需要引用该对象的values
数组。
我最好的尝试是:
self.newArray = ko.observableArray([]);
for(var i = 0; i < self.array.length; i++) {
var obj = {
name: ko.observable("new " + self.array[i].name()),
values: ko.observableArray(self.array[i].values())
};
obj.sum = ko.computed({
read: function() {
var res = 0;
for (var j = 0; j < obj.values().length; j++)
res += obj.values()[j];
return res;
},
owner: obj
});
self.newArray.push(obj);
}
问题是对values
可观察数组的引用以某种方式丢失了。也就是说,在第一次计算时,每个对象得到他的值的总和,但最后,每个计算得到的数据中最后对象的总和。
我尝试过,并且没有计算的owner
部分,仍然会传输引用。错误显然在小提琴中可见,我设置了三个按钮来改变每个值数组。
我也尝试将其设置为一个类:
function Obj(name, values) {
...
}
self.newArray.push(new Obj("first", [1, 2, 3]);
但同样的事情发生了。
答案 0 :(得分:2)
排序答案:使用ko.utils.arrayForEach
代替手动for
循环:
ko.utils.arrayForEach(self.array, function(item) {
var obj = {
name: ko.observable("new " + item.name()),
values: ko.observableArray(item.values())
};
obj.sum = ko.computed({
read: function() {
var res = 0;
for (var j = 0; j < obj.values().length; j++)
res += obj.values()[j];
return res;
},
owner: obj
});
self.newArray.push(obj);
});
演示JSFiddle。
很长的答案:你已经咬过这样一个事实,即在JavaScript中变量是函数范围的,所以你的for
循环不创建三个本地obj
变量但重用相同的一个变量,结合闭包的工作方式,最终会得到所有计算引用的最后一个值:
您可以通过将for
正文包装在一个立即执行的函数中来解决此问题:
for(var i = 0; i < self.array.length; i++) {
(function(){
var obj = {
name: ko.observable("new " + self.array[i].name()),
values: ko.observableArray(self.array[i].values())
};
obj.sum = ko.computed({
read: function() {
var res = 0;
for (var j = 0; j < obj.values().length; j++)
res += obj.values()[j];
return res;
},
owner: obj
});
self.newArray.push(obj);
})();
}
演示JSFiddle。