2012-03-06 55 views
185

在淘汰賽JS我看到聲明視圖模型爲兩種:差異聲明爲對象文本VS功能

var viewModel = { 
    firstname: ko.observable("Bob") 
}; 

ko.applyBindings(viewModel); 

或:

var viewModel = function() { 
    this.firstname= ko.observable("Bob"); 
}; 

ko.applyBindings(new viewModel()); 

什麼是兩者之間的區別,如果有的話?

我確實在knockoutjs google group上找到了this discussion,但它並沒有給我一個滿意的答案。

我明白了一個道理,如果我想用一些數據來初始化模式,例如:

var viewModel = function(person) { 
    this.firstname= ko.observable(person.firstname); 
}; 

var person = ... ; 
ko.applyBindings(new viewModel(person)); 

但是如果我不這樣做,不要緊,我選擇哪一種風格?

+0

我不相信有什麼區別。我通常使用構造函數模式,因爲我經常使用的方法更傾向於在'prototype'(通常是從服務器獲取數據並相應更新視圖模型的方法)上聲明。然而,你仍然可以很明顯地將它們聲明爲對象字面量的屬性,所以我不能真正看到差異。 – 2012-03-06 18:17:52

+4

這與knockout沒什麼關係,並且所有的事情都是通過JavaScript實現自定義對象的實例化來實現的 – zzzzBov 2012-03-06 19:01:45

+1

@Kev如果viewModel是一個構造函數,就像你在UpperCase中寫的一樣,就像var PersonViewModel = function(){...} ; – Elisabeth 2013-04-23 19:36:57

回答

242

使用函數來定義視圖模型有兩個好處。

主要優點是您可以立即訪問值爲this的值,該值等於正在創建的實例。這意味着,你可以這樣做:

var ViewModel = function(first, last) { 
    this.first = ko.observable(first); 
    this.last = ko.observable(last); 
    this.full = ko.computed(function() { 
    return this.first() + " " + this.last(); 
    }, this); 
}; 

所以,你的計算觀察到的可以綁定到的this適當的價值,即使從不同範圍調用。

一個對象文本,你必須做的:

var viewModel = { 
    first: ko.observable("Bob"), 
    last: ko.observable("Smith"), 
}; 

viewModel.full = ko.computed(function() { 
    return this.first() + " " + this.last(); 
}, viewModel); 

在這種情況下,你可以在計算觀察到的直接使用viewModel,但它得到的評價立即(默認),所以你不能在對象文字中定義它,因爲viewModel直到對象文字關閉後才定義。許多人不喜歡你的視圖模型的創建沒有被封裝到一個調用中。

您可以用來確保this總是合適的另一種模式是在函數中設置一個等於適當值this的變量,然後使用它。這將是這樣的:

var ViewModel = function() { 
    var self = this; 
    this.items = ko.observableArray(); 
    this.removeItem = function(item) { 
     self.items.remove(item); 
    } 
}; 

現在,如果你是在一個單獨的項目的範圍和呼叫$root.removeItemthis值實際上將數據在這一水平的限制(這將是該項目)。通過在這種情況下使用self,您可以確保將其從整體視圖模型中移除。

另一種選擇是使用bind,如果不受支持,則由現代瀏覽器支持並由KO添加。在這種情況下,它看起來像:

var ViewModel = function() { 
    this.items = ko.observableArray(); 
    this.removeItem = function(item) { 
     this.items.remove(item); 
    }.bind(this); 
}; 

還有很多,可以在這個題目,很多模式,你可以探索(如模塊模式和揭示模塊模式)可以說,但基本上使用函數給出您可以更靈活地控制對象的創建方式以及引用實例專用變量的能力。

+1

很棒的回答。我經常使用一個函數(使用揭示模塊模式)來處理像viewmodels這樣的複雜對象。但對於簡單的模型,我使用了一個函數,所以我可以在一個地方處理所有事情。 – 2012-03-06 23:40:00

+1

@JohnPapa - 剛剛在淘汰賽中觀看你的PluralSight視頻(剛過半程 - 巧合的是,只是看了關於對象字面與功能的部分)。真的很好,並幫助了一分錢的下降。僅此一個月就能獲得一個月的訂閱。 – Kev 2012-03-07 11:41:17

+0

@Kev - 謝謝。很高興你從中獲得價值。有些並不關心這個模塊,因爲它不是一個真正的Knockout概念,更多的是JavaScript模式。但是我發現,隨着Knockout的進一步發展,這些概念真的幫助我創建更清潔更穩定的代碼。無論如何,很高興你喜歡它:) – 2012-03-07 14:31:39

12

我使用不同的方法,儘管相似的:

var viewModel = (function() { 
    var obj = {}; 
    obj.myVariable = ko.observable(); 
    obj.myComputed = ko.computed(function() { return "hello" + obj.myVariable() }); 

    ko.applyBindings(obj); 
    return obj; 
})(); 

幾個原因:

  1. 不使用this,其可以混亂內ko.computed用於當s等
  2. 我的視圖模型是一個singleton,我不需要創建多個實例(即new viewModel()
+0

這是揭示模塊模式,如果沒有錯誤。很好的答案,但問題不在於這種模式。 – Phil 2013-07-23 21:43:21

+0

@ paul:抱歉,要求提供舊線程。你說'我的viewModel是一個單例,我不需要創建多個實例(即new viewModel())',但是不清楚你想說什麼'我不需要創建多個實例'提供更多用法,以便了解您的方法的優勢。謝謝 – Mou 2015-05-29 11:07:22

+0

IMO,您將ViewModel聲明爲'function'的原因之一是您會多次執行它。然而,在我的例子中,它是一個立即調用的匿名函數,所以它不會被創建多次。它與上面例子中的對象文字非常相似,但給你更多的隔離 – paulslater19 2015-05-29 12:34:45