初学knockoutjs记录4——Computed observables依赖监控(1 Using computed observables使用计算监控属性)
Computed Observables 计算监控属性
如果你已经有一个firstName的监控属性和另一个lastName的监控属性,你想要显示全名是该怎么办呢?这时就该引入computed observables组合监控属性--它的功能是依赖于一个或多个监控属性,并在任意一个依赖变化时自动更新。
例如,给定如下的view model
function AppViewModel(){ this.firstName = ko.ovservable('Bob'); this.lastName = ko.ovservable('Smith'); }
...你可以在其中增加一个计算监控属性来返回全名:
function AppViewModel(){ // .... leave firstName and lastName unchanged... this.fullName = ko.computed(function(){ return this.firstName() + " " + this.lastName(); }, this); }
现在,你可以将其绑定到UI元素上,例如:
The name is <span data-bind="test: fullName"></span>
无论什么时候firstName或者lastName变化,其中的fullName都会自动更新(你的计算监控属性声明的函数会在它的任意一个依赖每次变化时都被调用,任何你返回的值都会被传递给监控属性绑定的UI元素或者其它计算监控属性)。
Dependency chains just work 依赖链的工作机制
当然,如果你想要,那么你可以为计算监控属性创建整个依赖链,例如:
一个叫做items的监控属性表示一个item的集合;
另外一个叫做selectedIndexes的监控属性用于存储被选中的item的索引;
一个叫做selectedItems的计算监控属性返回选中索引(selectedIndexes)对应的item的对象数组;
另外一个计算监控属性依赖于任何一个选中的item(selectedItems)是否拥有一些属性(例如being new 或者 being unsaved)来返回true或false,一些UI元素,例如一个按钮,基于这个返回值来决定是enabled或者disabled.
改变items或者selectedIndexes会影响到计算监控属性的依赖链,反过来会更新绑定到它们的UI元素。
Managing 'this' 管理this
ko.computed的第二个参数(上边例子中的this)被定义为声明计算监控属性的this的引用值,没有它,就不能访问到this.firstName()或者this.lastName()。有经验的javascript程序员会认为这是显而易见的,但是对新手来说可能会比较奇怪(C#或Java语言从不要求设置一个this的值,但是javascript需要,因为默认情况下,它们的函数本身并不是任何对象的一部分)
A popular convention that simplifies things 一个约定俗称的规约就是简化
有一个通常的约定做法就是避免总是去跟踪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被函数闭包封闭,它在任意内部嵌套函数都是可用和一致的,例如内部的计算监控属性声明。这一约定非常有用,尤其是在使用事件处理时,你可以看到许多相关的例子。
Pure computed observables 纯计算监控属性
如果你的计算监控属性仅是简单的计算并返回基于监控依赖的值,那么比ko.computed更好的选择是使用ko.pureComputed,例如
this.fullName = ko.pureComputed(function(){ return this.firstName() + " " + this.lastName(); }, this);
一旦你的计算被声明为纯净的(那也就是说,你的计算函数不会直接修改其它对象或是状态),Knockout能够更高效的管理它的再评估和内存使用,Knockout能够在没有其它代码对其有激活的依赖时对它进行自动的暂停或释放。
纯计算监控在Konckout3.2.0中被引入,更多的例子请参见:more about pure computed observables.
Forcing computed observables to always notify subscribers 强制计算属性总是通知订阅者
当一个计算监控属性返回一个基元类型时(如number, string, boolean, 或者 null),监控属性的依赖通常只有在值真实变化时才会被通知,但是你可以使用内置的通知扩展来确保计算监控属性的订阅者在更新时能够及时得到通知,即使更新后的值依然相同,你可以像下边这样使用该扩展:
myViewModel.fullName = ko.pureComputed(function(){ return myViewModel.firstName() + " " + myViewModel.lastName(); }).extend({ notify: 'always' });
Delaying and/or suppressing change notifications 延迟或禁用更新通知
通常情况下,计算监控属性的依赖一旦变化,那么它会立刻更新并通知订阅者,但是如果一个计算监控属性如果包含有太多的依赖或者是会引起代价昂贵的更新,为了更好的性能,你可以限制或者禁用计算监控属性的更新和通知,使用该rateLimit 扩展的示例如下:
// ensure updates no more than once pre 50-millisecond preiod myViewModel.fullName.extend({ rateLimit: 50 })
Detemining if a property is a computed observable 检测一个属性是否是计算监控属性
在某些场景下,可能需要使用编程方式检测你处理的属性是否是一个计算监控属性,Knockout提供了一个工具函数,ko.isComputed。例如,你可以用它将计算监控属性的从你发回服务端的数据中排除掉:
for (var prop in myObject) { if (myObject.hasOwnProperty(prop) && !ko.isComputed(myObject[prop])){ result[prop] = myObject[prop]; } }
此外,Knockout还提供了一些类似的操作监控属性和计算监控属性的工具函数:
ko.isObservable -- 当为监控属性,监控属性或者计算监控属性是返回true
ko.isWritableObservable -- 当为监控属性,监控属性或者可写计算监控属性时返回true(也可写作 ko.isWriteableObservable)。
When the computed observable is only used in you UI 当你仅是在UI上使用计算监控属性时
如果你仅仅只想要在UI上计算全名时你可以像下边的例子中这样声明你的计算监控属性:
function AppViewModel(){ // ... leave firstName and lastName unchanged ... this.fullName = function() { return this.firstName() + " " + this.lastName(); }; }
现在,你可以像调用方法一样在你的UI元素上绑定它:
The name is <span data-bind="text: fullName()"></span>
Knockout会在内部创建一个计算监控属性用来检测这个监控属性的依赖,并且在该关联的元素被移除时自动的销毁它。