2013-02-19 22 views
3

我知道這是一個JavaScript本身的問題(或行爲),而不是Backbone的擴展方法,但我想知道什麼是避免它的最佳策略。骨幹:原型對象的惱人行爲

讓我們更好地把它放在代碼:

var MyModel = Backbone.Model.extend({ 
    value: 0, 
    values: [] 
}); 

var myFirstModel = new MyModel(); 

myFirstModel.value // 0, as expected 
myFirstModel.values // [], as expected 

var mySecondModel = new MyModel(); 

mySecondModel.value = 2; 
mySecondModel.values.push(2) 

mySecondModel.value // 2, as expected 
mySecondModel.values // [2], as expected 

myFirstModel.value // 0, as expected 
myFirstModel.values // [2], ... WAT!!! 

我明白,這個問題是我不是,我只是在數值變量,在操作mySecondModel.values分配一個新的值原型,也就是MyModel.prototype.values(當然與其他任何對象都有同樣的問題)

但是這很容易搞砸了。最直觀的是把它們當作INSTANCE變量,而不是每個實例通用的變量(基於類的語言中的靜態變量或類變量)。

到目前爲止,但是現在我發現一般的解決方法是將每個變量初始化initialize方法,如:

var MyModel = Backbone.Model.extend({ 
    initialize: function() { 
    this.value = 0; 
    this.values = []; 
    } 
}); 

這樣,一切正常,即使它不會是neccesary對於一個簡單的值(比如this.value),我發現在任何情況下堅持這個原則都容易得多。

我不知道是否有一些更好的(更優雅,更清晰)解決了這個問題

回答

2

這是JavaScript的原型繼承的效果和事實Array對象是引用類型。您傳遞給extend的對象的鍵/值對將被複制到MyModel的原型上,以便它們將由MyModel的所有實例共享。因爲values是一個數組,所以當您修改它時,將修改每個實例的數組。

你在做什麼initialize裏面設置values叫做陰影原型,它是解決這個問題的正確方法。

這就是說,在Backbone.Model的情況下,如果你正在嘗試處理模型的屬性,你可以使用defaults功能提供默認值是這樣的:

var MyModel = Backbone.Model.extend({ 
    defaults: function() { 
    return { 
     value: 0, 
     values: [] 
    } 
    } 
}); 

同樣,這只是屬性的一個實例。

var inst = new MyModel(); 

// The defaults will be created for each new model, 
// so this will always return a new array. 
var values = inst.get('values'); 

對於你在做什麼,你在哪裏上的模型本身指定的屬性,它是由你來設定的initialize內的違約,因爲你做了。

+0

很好的回答!事實上,我簡化了這個例子,我沒有使用Backbone Model,但是使用我自己的Controller模型,我只是在Backbone的擴展中混合使用Controller.extend = Backbone.Model.extend;然後我發現我討論的這件令人討厭的事情。這就是爲什麼我沒有使用模型的屬性。順便說一句,我已經理解了原型的東西,但你解釋得很清楚。用於解釋「遮蔽原型」技術以及區分模型屬性和模型屬性的額外榮譽。 – opensas 2013-02-19 07:11:02

1

我也偶然發現了這個問題,並在模型中定義了一個defaults方法來解決這個問題。

var MyModel = Backbone.Model.extend({ 
    defaults: function() { 
    return { 
     value: 0, 
     values: [] 
    } 
    } 
}); 
2

你是不是故意設置valuevalues爲骨幹的屬性?如果您在實例上設置屬性,而不是將它們放入擴展骨幹模型定義中,則它可能按照您的預期工作。

var MyModel = Backbone.Model.extend(); 

var myFirstModel = new MyModel({ 
    value: 0, 
    values: [] 
}); 

console.log(myFirstModel.get('value'); // 0 
console.log(myFirstModel.get('values'); // [] 

var mySecondModel = new MyModel({ 
    value: 2, 
    values: [2] 
}); 

//mySecondModel.value = 2; 
//mySecondModel.values.push(2) 

console.log(mySecondModel.get('value'); // 2 
console.log(mySecondModel.get('values'); // [2] 

console.log(myFirstModel.get('value'); // 0 
console.log(myFirstModel.get('values'); // [] 

jsFiddle,檢查控制檯日誌。

+0

我希望他們有一個默認值,然後處理實例值而不會混淆原型。 – opensas 2013-02-19 07:04:50