我试图理解将observable保持为函数或将其设置为对象之间的区别
我的可观察项目:
self.SelectedItem = ko.observable();
我的观点:
<div class="collapse" data-bind="with: SelectedItem">
@Html.Action("Profile", "Team")
</div>
<div class="collapse" data-bind="with: ItemForEditing">
@Html.Action("EditProfile", "Team")
</div>
从网格中选择项目:
ko.utils.extend(TeamManager.prototype, {
selectItem: function (item) {
if (typeof item == "undefined") return;
this.SelectedItem(item);
//this.SelectedItem = item;
ko.mapping.fromJS(ko.mapping.toJS(item), this.ItemForEditing);
},
acceptItem: function (itemData) {
ko.mapping.fromJS(itemData, {}, this.SelectedItem);
},
为什么我对视图的绑定仅在可观察SelectedItem
作为函数调用时才起作用,例如this.SelectedItem(item);
,而不是作为赋值,例如this.SelectedItem = item;
。后者导致部分视图无法呈现。
如果我像this.SelectedItem(item);
这样使用它一切都好 - 为什么我需要这样使用它?
答案 0 :(得分:3)
那只是how observables work。 knockout observable将您的属性/变量转换为函数。要从中获取值,您必须在没有参数的情况下调用该函数。要设置该值,请使用新值调用它。使用新值调用函数的行为允许knockout更新任何订阅,包括绑定。
当你这样做时:
this.SelectedItem = item;
SelectedItem
已不再是observable
,已更新为直接指向item
,因此不会更新任何绑定。
话虽如此,如果你在现代环境中工作,淘汰的主要作者之一已经a plugin允许更常见的属性访问,其中一项任务可以工作。
答案 1 :(得分:2)
在knockout.js中,所有可观察对象都形成为包含数据的函数。由于没有真正容易等待跟踪=
对象的更改,因此knockoutjs的开发人员决定不使用对象的getter / setter方法,而是使用函数是实现跟踪更改的最简单方法。 / p>
对象上的Getter / Setter是旧版浏览器不具备的新功能,但可以调用JavaScript函数,并且可以访问调用此方法的方法arguments.callee
。
https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Fonctions/arguments/callee
为了能够实现跟踪,无论何时调用observable方法,它都将使用被调用者构建依赖树,这样,KnockoutJS能够知道在调用observable时要更新的内容。
假设你有这个对象:
t.fun = ko.Observable(10)
每当您使用该方法时。 t.fun()
您实际上正在调用该方法,但是当fun
的值发生变化时,淘汰会将此地点注册为需要被称为字母的地方。
当您致电t.fun(value)
时,它会触发更改并再次调用已调用的地方。
这导致了为什么在淘汰赛中,每个观察者必须被召唤至少一次,才能抓住任何变化。如果您不以任何方式致电t.fun()
,则knockoutjs不知道您的代码的这一部分取决于t.fun
。
此外,只要您将t.fun
影响到其他任何事情......
t.foo = t.fun
。
t.foo
应该与t.fun
完全相同。
因此,如果在对象中设置了值。与其他语言不同,它始终是一种价值,t.fun = 1
不会更新t.fun
,而是将t.fun
的值替换为1
。 JavaScript可能会对基本类型进行更新,但在对象的情况下,您正在影响一个普通的新值,并且JavaScript无法知道该值是否已更改。
AngularJS通过将旧值与新值进行比较来检查值的变化。 KnockoutJS只是跟踪值的变化,因此不需要进行任何比较。
这是一个示例小提琴https://jsfiddle.net/gatnfbao/1/
var ViewModel = function(first, last) {
this.firstName = first;
this.lastName = ko.observable(last);
this.fullName = ko.computed(function() {
// Knockout tracks dependencies automatically.
// It knows that fullName depends on firstName and lastName,
// because these get called when evaluating fullName.
return this.firstName + " " + this.lastName();
}, this);
};
ko.applyBindings(new ViewModel("Planet", "Earth")); // This makes
您可以看到计算字段正在使用this.firstName
和this.lastName()
,它会告诉已淘汰computed
字段是基于lastName
。当knockoutjs启动时,它将尝试调用每个ko.computed
变量以将它们添加到依赖关系树中。您可以在我们的viewModel中看到,正确计算了字段fullname:Planet Earth!
。但是,如果您修改输入文本中的字段,它将不会更改ko.computed
中的任何内容。但是,如果您更改“姓氏”字段,它会考虑两个字段来更新fullName
,因为它们都存在。如果您修改firstName
,则只会在lastName
更改后才会看到结果。
但现在,我们将更改一些代码,以便您了解当您修改lastName
时,您会发现计算值使用firstName
的正确值作为{{的副作用1}}是一个可观察但lastName
不是......让我们删除所有可观察者! https://jsfiddle.net/gatnfbao/2/
firstName
请注意,现在计算字段使用var ViewModel = function(first, last) {
this.firstName = first;
this.lastName = last;
this.fullName = ko.computed(function() {
return this.firstName + " " + this.lastName;
}, this);
};
ko.applyBindings(new ViewModel("Planet", "Earth")); // This makes
而不是this.lastName
。现在,淘汰赛对this.lastName()
值依赖的内容一无所知。
computed
将使用值ko.computed
和Planet
调用一次,但由于它没有使用可观察对象,Earth
不知道发生了什么那里。因此,如果您修改字段ko.computed
或firstName
,则永远不会更新lastName
。它是用初始值计算的,但它不包含任何可观察的值。