若是你有一个监控的属性firstName
和另外一个lastName
,但你想显示全名怎么办? 这就是引入计算监控的缘由-这是依赖于一个或多个其余的observables函数,不管这些依赖对象何时发生改变,它都将自动更新。
例如,下面给了一个view model 类,javascript
function AppViewModel() { this.firstName = ko.observable('Bob'); this.lastName = ko.observable('Smith'); }
您能够添加一个computed observable来返回全名:html
function AppViewModel() { this.firstName = ko.observable('Bob'); this.lastName = ko.observable('Smith'); // ... 保留firstName和lastName不变 ... this.fullName = ko.computed(function() { return this.firstName() + " " + this.lastName(); }, this); }
如今你能够绑定到UI元素,例如:java
The name is <span data-bind="text: fullName"></span>
每当firstName
或lastName
的值更改时,它们都将更新(其任何依赖项发生更改时,都会调用你的求值函数,而且您返回的任何值都将传递给监控者,例如UI元素或其余计算监控)。程序员
固然,若是你愿意,你能够建立整个计算监控的链。例如,您可能有:编程
items
表示一个集合selectedIndexes
存储用户选择集合某一项的索引值selectedItems
以数组的形式返回选中的对象集合selectedItems
里是否有选择项返回true
或false
(就像是空的或者未保存)。一些UI元素,好比按钮,可能根据这个值来判断按钮是否可用。对items
或selectedIndexes
的更改将波及到计算监控的链,这反过来会更新绑定到它们的UI元素。数组
ko.computed的第二个参数(咱们在上面的例子中传递this的位置)在执行计算监控时定义了它的值。若是没有传递它,它不可能引用this.firstName()
或this.lastName()
。经验丰富的JavaScript编程人员会认为这是显而易见的,但若是你仅仅了解JavaScript,它可能看起来很奇怪。(像C#和Java这样的语言历来不但愿程序员能够为this
设置一个值,可是JavaScript能够,由于它的函数自己在默认状况不是任何对象的一部分。)服务器
一种流行的处理方式闭包
有一个流行的约定,避免了老是须要跟踪this:若是你的viewmodel的构造函数将this赋值到一个不一样的变量(一般叫作self
),而后在你的viewmodel里可使用self
,而没必要担忧this被从新定义以指代别的东西。 例如:函数
function AppViewModel() { var self = this; self.firstName = ko.observable('Bob'); self.lastName = ko.observable('Smith'); self.fullName = ko.computed(function() { return self.firstName() + " " + self.lastName(); }); }
由于self
在函数闭包中捕获,因此它在任何嵌套函数(例如在计算监控中的求值程序)中保持可用和一致。当涉及到事件处理程序时,这个约定甚至更有用,你将在许多在线实例中看到。工具
若是你想简单地计算并返回一个基于一些监控依赖的值,那么最好将其声明为ko.pureComputed
而不是ko.computed
。 例如:
this.fullName = ko.pureComputed(function() { return this.firstName() + " " + this.lastName(); }, this);
因为这个计算被声明为纯的(即,执行器不直接修改其余对象或状态),KO能够更有效地管理其从新评估和内存使用。若是没有其余代码对它有活动依赖,Knockout将自动挂起或释放它。
当一个computed observable返回一个原始值(一个数字,字符串,布尔,或null),依赖监控一般只有在值实际改变时才进行通知。可是,可使用内置notify extender
来确保computed observable的订阅者老是在更新时通知,即便该值是相同的。 您能够这样使用扩展器:
myViewModel.fullName = ko.pureComputed(function() { return myViewModel.firstName() + " " + myViewModel.lastName(); }).extend({ notify: 'always' });
一般状况下,一个计算监控对象只要发生改变就会当即通知订阅者。可是一个计算监控对象有不少依赖或触发一直更新,代价会很大,经过限制或延迟监控到的更改通知,能够得到更好的性能。可使用频率限制扩展器来完成,以下:
// 确保每50毫秒内通知改变不超过一次 myViewModel.fullName.extend({ rateLimit: 50 });
在某些状况下,以程序的方式肯定某个属性是不是计算监控对象是颇有用的。 KO提供了一个工具函数,ko.isComputed
来帮助处理这种状况。例如,您可能但愿从返回服务器的数据中排除计算监控值。
for (var prop in myObject) { if (myObject.hasOwnProperty(prop)&&!ko.isComputed(myObject[prop])) { result[prop] = myObject[prop]; } }
此外,KO提供了相似的功能,能够操做监控和计算监控:
ko.isWriteableObservable
)返回true。若是你只须要在UI中使用组合全名,你能够声明它:
function AppViewModel() { // ... 保留firstName和lastName... this.fullName = function() { return this.firstName() + " " + this.lastName(); }; }
如今你绑定的UI元素变成方法调用,好比:
The name is <span data-bind="text: fullName()"></span>
KO将在内部建立一个计算监控,以便检测该监控表达式的依赖,而且在关联的元素在后面移除的时候自动释放它。