# Computed Observables 如果你有一个用于 firstName 的 observable 和另一个用于 lastName 的 observable,并且你想显示全名怎么办? 这就是计算 observable 的用武之地——这些函数依赖于一个或多个其他 observable,并且会在这些依赖项中的任何一个发生变化时自动更新。 例如,给定以下视图模型类, ``` function AppViewModel() { this.firstName = ko.observable('Bob'); this.lastName = ko.observable('Smith'); } ``` 你可以添加一个计算的 observable 来返回全名: ``` 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="text: fullName"></span> ` 并且它们将在 firstName 或 lastName 更改时更新(每次其任何依赖项更改时都会调用一次您的评估器函数,并且您返回的任何值都将传递给观察者,例如 UI 元素或其他计算出的可观察对象)。 ***** 一种简化事物的流行约定 有一个流行的约定可以避免完全跟踪这一点:如果您的视图模型的构造函数将对 this 的引用复制到一个不同的变量(传统上称为 self)中,那么您就可以在整个视图模型中使用 self 并且不必担心它被 重新定义以指代别的东西。 例如: ``` 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 在函数的闭包中被捕获,所以它在任何嵌套函数中保持可用和一致,例如计算 observable 的评估器。 当涉及到事件处理程序时,这个约定更加有用. ### Pure computed observables 如果您的计算 observable 只是根据一些 observable 依赖项计算并返回一个值,那么最好将其声明为 ko.pureComputed 而不是 ko.computed。 例如: ``` this.fullName = ko.pureComputed(function() { return this.firstName() + " " + this.lastName(); }, this); ``` 由于此计算被声明为纯计算(即,其评估器不直接修改其他对象或状态),因此 Knockout 可以更有效地管理其重新评估和内存使用。 如果没有其他代码对其有主动依赖,Knockout 将自动挂起或释放它。 ***** 强制计算的 observables 总是通知订阅者 当计算出的 observable 返回一个原始值(数字、字符串、布尔值或 null)时,通常仅在值实际发生变化时才会通知 observable 的依赖项。 但是,可以使用内置的通知扩展器来确保计算的 observable 的订阅者始终在更新时收到通知,即使值相同。 您可以像这样应用扩展器: ``` myViewModel.fullName = ko.pureComputed(function() { return myViewModel.firstName() + " " + myViewModel.lastName(); }).extend({ notify: 'always' }); ``` 确定一个属性是否是一个计算出的可观察对象 在某些情况下,以编程方式确定您是否正在处理计算出的 observable 很有用。 Knockout 提供了一个实用函数 ko.isComputed 来帮助解决这种情况。 例如,您可能希望从发送回服务器的数据中排除计算的 observable。 ``` for (var prop in myObject) { if (myObject.hasOwnProperty(prop) && !ko.isComputed(myObject[prop])) { result[prop] = myObject[prop]; } } ``` 此外,Knockout 提供了类似的函数,可以对 observables 和计算 observables 进行操作: ko.isObservable - 为 observables、observable 数组和所有计算的 observables 返回 true。 ko.isWritableObservable - 为 observables、observable 数组和可写计算 observables(也称为 ko.isWriteableObservable)返回 true。 当计算出的 observable 仅在您的 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 将在内部创建一个计算的 observable 以检测表达式所依赖的 observable,并在稍后删除关联元素时自动处理它。