当我用ko observables做一些繁重的计算时,我注意到了一个问题。
您可以在http://jsfiddle.net/dundanox/AyU8y/1/
找到问题的示例为了保持简短,我有一个输入字段和一个可观察的“val”
<input data-bind="value: val">
现在,有两种方法可以更改observable的值
1.手动在输入字段中键入(新)值
2.通过脚本分配(新)值,例如ViewModel.val(3.14)
设定值后,我会进行一些繁重的计算,例如:
var val = ViewModel.val(); // get current value, e.g. 3.14
for(var sum=0, ii=0; ii > imax; ii++)
sum += val
如果我通过脚本设置值(第二种方法),一切都很好。 但是如果我手动设置一个值(第一种方法),计算时间会多次爆炸!
我认为这是奇怪的行为,不应该。但我找不到问题。这是knockoutJS中的一个问题吗?
为了澄清它,使用以下代码一切都很好。
var val = 3.14;
for(var sum=0, ii=0; ii > imax; ii++)
sum += val
我对这条线的理解
var val = ViewModel.val(); // get current value, e.g. 3.14
应该和我写的一样
var val = 3.14;
这似乎取决于我如何设置observable的值。为什么会这样?我该如何解决?
答案 0 :(得分:0)
答案 1 :(得分:0)
安德斯是对的!操作更昂贵,因为javascript需要在每次迭代时进行隐式类型转换。也许你听说过===
运算符,因为它比较了类型和值,不同于==
运算符,它只比较了值,但对你要比较的值进行了隐式类型转换。 / p>
希望它有所帮助!
答案 2 :(得分:0)
问题的根本原因是当敲除通知输入的值更改时,它会从输入字段中读取新值并将其写回observable。
输入的值是一个字符串,这就是KO放入observable的内容。
如果您希望它是一个数字,那么您需要始终将值强制转换为数字。这样做的最佳方式(恕我直言)是通过 fn 扩展点。
ko.observable.fn['asNumber'] = function (defaultValue) {
var target = this;
var interceptor = ko.computed({
read: target,
write: function (value) {
var parsed = parseFloat(value);
var manualNotifyFlag = false;
if (isNaN(parsed)) {
parsed = defaultValue;
manualNotifyFlag = (target() === parsed);
}
if (!manualNotifyFlag) {
target(parsed);
} else {
target.valueHasMutated();
}
}
});
interceptor(target()); // Ensure target is properly initialised.
return interceptor;
}
创建我们的observable使用以下
val: ko.observable(3.14).asNumber(0)
现在,当设置了observable的值时,无论您是使用数字类型手动执行,还是使用字符串通过元素更改事件进行淘汰,observable的值将被强制为数字。
这样可以避免将parseFloats放在代码库中。
我已更新fiddle以显示此内容。
此外,扩展程序中的parseFloat语句可以轻松改进以支持任何全球化引擎,再次只需在代码库中的一个位置执行此操作
// Using the jQuery Globalize library from http://github.com/jquery/globalize
var parsed = (typeof (value) === "string" ?
Globalize.parseFloat(value) :
parseFloat(value));