若是你有一個監控的屬性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將在內部建立一個計算監控,以便檢測該監控表達式的依賴,而且在關聯的元素在後面移除的時候自動釋放它。